diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..999c481 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,36 @@ + +name: Test + +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + - master + - develop + +jobs: + spec: + runs-on: ubuntu-latest + name: Ruby ${{ matrix.ruby }} + strategy: + fail-fast: false + matrix: + ruby: + - "2.1" + # - "2.2" Error: You may have encountered a bug in the Ruby interpreter or extension libraries. + - "2.3" + - "2.4" + - "2.5" + - "2.6" + - "2.7" + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Run tests + run: bundle exec rake diff --git a/.ruby-version b/.ruby-version index 3e3c2f1..6a81b4c 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.1.1 +2.7.8 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8349955..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: ruby -rvm: - - 2.0.0 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0c356e8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +ARG RUBY_VERSION=2.7.8 + +FROM ruby:$RUBY_VERSION AS base + +WORKDIR /app diff --git a/README.md b/README.md index cdefd1c..9705389 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Some alternatives to ToJson and primary diferences. ### ToJson vs JSONBuilder + JSONBuilder is very slow (but not as slow as Jsonify) + DSL relys on method_missing for JSON attribute names - + ### ToJson vs Jsonify + Jsonify is the slowest JSON serialization option I am aware of + DSL relys on method_missing for the JSON attribute names @@ -199,6 +199,23 @@ Jbuilder - simple 6.180000 0.000000 6.180000 ( 6.182140) Jbuilder - complex 22.600000 2.240000 24.840000 ( 24.861366) ``` +Ruby 2.7.8 + +``` +Serialize 500,000 objects separately: + user system total real +ToJson (class) - simple 0.990960 0.000810 0.991770 ( 0.991792) +ToJson (class) - parallel 0.001599 0.017075 37.137801 ( 2.362301) +(8000000 ops) +ToJson (class) - complex 7.461308 0.002083 7.463391 ( 7.464256) +ToJson (block) - simple 3.501560 0.000000 3.501560 ( 3.501646) +ToJson (block) - complex 10.815699 0.000428 10.816127 ( 10.816804) +Jbuilder - simple 5.677831 0.001979 5.679810 ( 5.682258) +Jbuilder - complex 23.310981 0.001866 23.312847 ( 23.316103) +JSONBuilder - complex 28.786932 0.002175 28.789107 ( 28.796768) +jsonify - complex 48.479856 0.006111 48.485967 ( 48.503229) +``` + The real time used is the important figure. As can be seen ToJson using a class based serializer is 4.7 times faster than the fastest alternative. diff --git a/dip.yml b/dip.yml new file mode 100644 index 0000000..94ae392 --- /dev/null +++ b/dip.yml @@ -0,0 +1,36 @@ +version: '7.3' + +compose: + files: + - docker-compose.yml + +interaction: + sh: + description: Open a Bash shell within a Rails container (with dependencies up) + service: app + command: /bin/bash + + bundle: + description: Run Bundler commands + service: app + command: bundle + compose_run_options: [no-deps] + + rake: + description: Run Rake commands + service: app + command: bundle exec rake + +provision: + # # Remove old containers and volumes. + - dip compose down --volumes --remove-orphans + - docker volume create <%= ENV.fetch('COMPOSE_PROJECT_NAME', 'to_json') %>-history + + # Create mount points for specific directories. + - mkdir -p tmp + + # Build the development container + - dip compose build + + # Install gems + - dip bundle install diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..87b928f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +services: + app: + environment: + HISTFILE: /usr/local/hist/.bash_history + IRB_HISTFILE: /usr/local/hist/.irb_history + EDITOR: vi + + build: + context: . + args: + RUBY_VERSION: 2.7.8 + command: bundle exec puma -p 5001 -t 1:5 -w 2 + volumes: + - .:/app:cached + - bundle:/usr/local/bundle + - history:/usr/local/hist + tmpfs: + - /tmp + +volumes: + bundle: + history: + external: true + name: to_json-history diff --git a/test/benchmarks/Gemfile.lock b/test/benchmarks/Gemfile.lock index 7911836..567b400 100644 --- a/test/benchmarks/Gemfile.lock +++ b/test/benchmarks/Gemfile.lock @@ -7,29 +7,66 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (4.1.1) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - i18n (0.6.9) - jbuilder (2.0.7) - activesupport (>= 3.0.0, < 5) - multi_json (~> 1.2) - json (1.8.1) + actionview (7.1.4) + activesupport (= 7.1.4) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activesupport (7.1.4) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + base64 (0.2.0) + bigdecimal (3.1.8) + builder (3.3.0) + concurrent-ruby (1.3.4) + connection_pool (2.4.1) + crass (1.0.6) + drb (2.2.1) + erubi (1.13.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) + jbuilder (2.12.0) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + json (2.7.2) json_builder (3.1.7) activesupport (>= 2.0.0) json jsonify (0.4.1) multi_json (~> 1.3) - minitest (5.3.4) - multi_json (1.10.1) - oj (2.9.4) + loofah (2.22.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mini_portile2 (2.8.7) + minitest (5.25.1) + multi_json (1.15.0) + mutex_m (0.2.0) + nokogiri (1.15.6) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + oj (3.16.5) + bigdecimal (>= 3.0) + ostruct (>= 0.2) oj_mimic_json (1.0.1) - thread_safe (0.3.4) - tzinfo (1.2.1) - thread_safe (~> 0.1) + ostruct (0.6.0) + racc (1.8.1) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) PLATFORMS ruby @@ -41,3 +78,6 @@ DEPENDENCIES oj oj_mimic_json to_json! + +BUNDLED WITH + 2.1.4 diff --git a/test/test_to_json.rb b/test/test_to_json.rb index ec5babd..10c78bd 100644 --- a/test/test_to_json.rb +++ b/test/test_to_json.rb @@ -1,11 +1,26 @@ -require 'minitest_helper' +require "minitest_helper" + +class TestToJson < Minitest::Test + class Subject < ToJson::Serializer + def serialize(controller, station, timestamps, media_type_scope: :default) + put :controller, controller + put :station, station + put :timestamps, timestamps + put :media_type_scope, media_type_scope + end + end -class TestToJson < MiniTest::Unit::TestCase def test_that_it_has_a_version_number refute_nil ::ToJson::VERSION end - def test_it_does_something_useful - assert false + def test_instance_method_will_return_json + assert_equal Subject.new.json!(:controller, :station, [:timestamps], media_type_scope: :media_files), + '{"controller":"controller","station":"station","timestamps":["timestamps"],"media_type_scope":"media_files"}' + "\n" + end + + def test_class_method_will_return_json + assert_equal Subject.json!(:controller, :station, [:timestamps], media_type_scope: :media_files), + '{"controller":"controller","station":"station","timestamps":["timestamps"],"media_type_scope":"media_files"}' + "\n" end end diff --git a/to_json.gemspec b/to_json.gemspec index 1d3aa29..750413d 100644 --- a/to_json.gemspec +++ b/to_json.gemspec @@ -8,7 +8,6 @@ Gem::Specification.new do |spec| spec.name = "to_json" spec.version = ::ToJson::VERSION spec.authors = ["Andrew Hacking"] - spec.date = Date.today.to_s spec.email = ["ahacking@gmail.com"] spec.homepage = "https://github.com/ahacking/to_json" spec.summary = %q{A pragmatic DSL for fast JSON serialization} @@ -17,12 +16,11 @@ Gem::Specification.new do |spec| spec.files = `git ls-files`.split($/) 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.add_dependency 'oj', '>= 2.9.4' - spec.add_development_dependency "bundler", "~> 1.3" + spec.add_development_dependency "bundler" spec.add_development_dependency "rake" spec.add_development_dependency "minitest" end