diff --git a/lib/turbostreamer.rb b/lib/turbostreamer.rb index 788d6ab..0da8a6a 100644 --- a/lib/turbostreamer.rb +++ b/lib/turbostreamer.rb @@ -1,9 +1,13 @@ require 'stringio' -require 'turbostreamer/key_formatter' + require 'turbostreamer/errors' class TurboStreamer + autoload :Handler, 'turbostreamer/handler' + autoload :Template, 'turbostreamer/template' + autoload :KeyFormatter, 'turbostreamer/key_formatter' + BLANK = ::Object.new ENCODERS = { @@ -228,18 +232,23 @@ def self.key_formatter=(formatter) @@key_formatter = formatter end - def self.set_default_encoder(mime, encoder, default_options={}) - if encoder.is_a?(Symbol) - @@default_encoders[mime] = get_encoder(mime, encoder) + def self.set_default_encoder(mime, encoder, default_options=nil) + @@default_encoders[mime] = if encoder.is_a?(Symbol) + get_encoder(mime, encoder) else - @@default_encoders[mime] = encoder + encoder end - @@encoder_options[encoder] = default_options + + @@encoder_options[encoder] = default_options if default_options end def self.set_default_encoder_options(encoder, options) @@encoder_options[encoder] = options end + + def self.has_default_encoder_options?(encoder) + @@encoder_options.has_key?(encoder) + end def self.get_encoder(mime, key) require "turbostreamer/encoders/#{key}" diff --git a/lib/turbostreamer/dependency_tracker.rb b/lib/turbostreamer/dependency_tracker.rb index cd8cb1b..5985924 100644 --- a/lib/turbostreamer/dependency_tracker.rb +++ b/lib/turbostreamer/dependency_tracker.rb @@ -1,5 +1,3 @@ -require 'turbostreamer' - dependency_tracker = false begin diff --git a/lib/turbostreamer/handler.rb b/lib/turbostreamer/handler.rb index 0f7cf79..ae32d13 100644 --- a/lib/turbostreamer/handler.rb +++ b/lib/turbostreamer/handler.rb @@ -1,7 +1,8 @@ require "turbostreamer" require "active_support/core_ext" -# This module makes TurboStreamer work with Rails using the template handler API. +# This module makes TurboStreamer work with Rails using the template handler +# API. class TurboStreamer class Handler @@ -12,11 +13,7 @@ def self.supports_streaming? true end - # TODO: setting source=nil is for rails 5.x compatability, once unsppored - # source can be a required param and - # `source = template.source if source.nil?` can be removed - def self.call(template, source=nil) - source = template.source if source.nil? + def self.call(template, source) # this juggling is required to keep line numbers right in the error %{__already_defined = defined?(json); json||=TurboStreamer::Template.new(self, output_buffer: output_buffer || ActionView::OutputBuffer.new); #{source} json.target! unless (__already_defined && __already_defined != "method")} diff --git a/lib/turbostreamer/key_formatter.rb b/lib/turbostreamer/key_formatter.rb index 120716c..c698741 100644 --- a/lib/turbostreamer/key_formatter.rb +++ b/lib/turbostreamer/key_formatter.rb @@ -1,33 +1,29 @@ -require 'active_support/core_ext/array' +class TurboStreamer::KeyFormatter + def initialize(*args) + @format = {} + @cache = {} -class TurboStreamer - class KeyFormatter - def initialize(*args) - @format = {} - @cache = {} - - options = args.extract_options! - args.each do |name| - @format[name] = [] - end - options.each do |name, paramaters| - @format[name] = paramaters - end + options = args.extract_options! + args.each do |name| + @format[name] = [] end - - def initialize_copy(original) - @cache = {} + options.each do |name, paramaters| + @format[name] = paramaters end + end + + def initialize_copy(original) + @cache = {} + end - def format(key) - @cache[key] ||= @format.inject(key.to_s) do |result, args| - func, args = args - if ::Proc === func - func.call result, *args - else - result.send func, *args - end + def format(key) + @cache[key] ||= @format.inject(key.to_s) do |result, args| + func, args = args + if ::Proc === func + func.call result, *args + else + result.send func, *args end end end -end +end \ No newline at end of file diff --git a/lib/turbostreamer/railtie.rb b/lib/turbostreamer/railtie.rb index 8d58ea1..1285264 100644 --- a/lib/turbostreamer/railtie.rb +++ b/lib/turbostreamer/railtie.rb @@ -1,15 +1,25 @@ require 'rails/railtie' -require 'turbostreamer/handler' -require 'turbostreamer/template' - -require File.expand_path('../../../ext/actionview/buffer', __FILE__) -require File.expand_path('../../../ext/actionview/streaming_template_renderer', __FILE__) class TurboStreamer class Railtie < ::Rails::Railtie initializer :turbostreamer do ActiveSupport.on_load :action_view do + # Require turbostreamer in here so it's only loaded if needed + require 'turbostreamer' + require File.expand_path('../../../ext/actionview/buffer', __FILE__) + require File.expand_path('../../../ext/actionview/streaming_template_renderer', __FILE__) + + # Register Turbostreamer with Rails ActionView::Template.register_template_handler :streamer, TurboStreamer::Handler + + # Setup the default for oj to be rails mode by default unless options + # have already been set + if TurboStreamer.default_encoder_for(:json).name == 'TurboStreamer::OjEncoder' + if !TurboStreamer.has_default_encoder_options?(:oj) + TurboStreamer.set_default_encoder_options(:oj, mode: :rails) + end + end + require 'turbostreamer/dependency_tracker' end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 006abcf..622d921 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,19 +2,15 @@ # installed gem $LOAD_PATH << File.expand_path('../lib', __FILE__) +require "minitest/reporters" +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new -require "active_support" +require 'turbostreamer' +require 'turbostreamer/railtie' require 'action_view' require 'action_view/testing/resolvers' -require 'turbostreamer' -require 'turbostreamer/handler' -require 'turbostreamer/template' - -require File.expand_path('../../ext/actionview/buffer', __FILE__) -require File.expand_path('../../ext/actionview/streaming_template_renderer', __FILE__) - require "active_support/testing/autorun" require 'mocha/minitest' diff --git a/test/turbo_streamer/options_test.rb b/test/turbo_streamer/options_test.rb index b9ff252..95afaea 100644 --- a/test/turbo_streamer/options_test.rb +++ b/test/turbo_streamer/options_test.rb @@ -3,12 +3,13 @@ class TurboStreamer::OptionsTest < ActiveSupport::TestCase setup do - @default_encoder = TurboStreamer.class_variable_get('@@default_encoders')[:json] - @default_options = TurboStreamer.class_variable_get('@@encoder_options').dup + @default_encoder = TurboStreamer.class_variable_get(:@@default_encoders).deep_dup + @default_options = TurboStreamer.class_variable_get(:@@encoder_options).deep_dup end teardown do - TurboStreamer.set_default_encoder(:json, @default_encoder, @default_options) + @default_encoder = TurboStreamer.class_variable_set(:@@default_encoders, @default_encoder) + @default_options = TurboStreamer.class_variable_set(:@@encoder_options, @default_options) end test 'setting default options' do diff --git a/test/turbo_streamer_template_test.rb b/test/turbo_streamer_template_test.rb index 9a36db7..601f23c 100644 --- a/test/turbo_streamer_template_test.rb +++ b/test/turbo_streamer_template_test.rb @@ -31,7 +31,7 @@ BLOG_POST_COLLECTION = 10.times.map{ |i| BlogPost.new(i+1, "post body #{i+1}", blog_authors.next) } COLLECTION_COLLECTION = 5.times.map{ |i| Collection.new(i+1, "collection #{i+1}") } -ActionView::Template.register_template_handler :streamer, TurboStreamer::Handler +TurboStreamer::Railtie.initializers.each(&:run) module Rails def self.cache @@ -539,4 +539,19 @@ def assert_collection_rendered(json, overrides = {}, *selector) assert_collection_rendered(json, {0 => 'CACHE HIT'}, 'key') end + test "timestamp precision" do + # Reset options for boot process and run rails initializers + TurboStreamer.class_variable_set(:@@default_encoders, {}) + TurboStreamer.class_variable_set(:@@encoder_options, Hash.new { |h, k| h[k] = {} }) + TurboStreamer::Railtie.initializers.each(&:run) + + ActiveSupport::JSON::Encoding.time_precision = 6 + + result = jbuild do |json| + json.object! { json.timestamp Time.at(1000000000, 500500, :usec) } + end + + assert_equal({"timestamp"=>"2001-09-08T20:46:40.500500-05:00"}, result) + end + end diff --git a/turbostreamer.gemspec b/turbostreamer.gemspec index 74ccc66..1e70b72 100644 --- a/turbostreamer.gemspec +++ b/turbostreamer.gemspec @@ -8,7 +8,10 @@ Gem::Specification.new do |spec| spec.email = ["jonbracy@gmail.com"] spec.homepage = "https://github.com/malomalo/turbostreamer" spec.summary = 'Stream JSON via a Builder-style DSL' - # spec.description = %q{} + spec.description = <<-DESC + TurboStreamer is a JBuilder-like DSL for building JSON that streams directly + to a string or IO + DESC spec.extra_rdoc_files = %w(README.md) spec.rdoc_options.concat ['--main', 'README.md'] @@ -17,12 +20,13 @@ Gem::Specification.new do |spec| spec.test_files = `git ls-files -- {test}/*`.split("\n") spec.require_paths = ["lib"] - spec.required_ruby_version = '>= 2.5' + spec.required_ruby_version = '>= 3.0' spec.add_runtime_dependency 'activesupport', '>= 5.0.0' spec.add_development_dependency "rake" spec.add_development_dependency "wankel" + spec.add_development_dependency 'minitest-reporters' spec.add_development_dependency "oj" spec.add_development_dependency "bundler" spec.add_development_dependency "mocha" @@ -34,6 +38,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'jbuilder' spec.add_development_dependency 'rabl' spec.add_development_dependency "appraisal", "~> 2.0" + spec.add_development_dependency "railties" # For running benchmark spec.add_development_dependency 'multi_json' # spec.add_development_dependency 'sdoc', '~> 0.4'