class TurboStreamer
This module makes TurboStreamer
work with Rails using the template handler API.
Constants
- BLANK
- DependencyTracker
- ENCODERS
- VERSION
Public Class Methods
# File lib/turbostreamer.rb, line 249 def self.default_encoder_for(mime) if @@default_encoders[mime] @@default_encoders[mime] else ENCODERS[mime].to_a.find do |key, class_name| next if !const_defined?(class_name) return get_encoder(mime, key) end ENCODERS[mime].to_a.find do |key, class_name| begin return get_encoder(mime, key) rescue ::LoadError next end end raise ArgumentError, "Could not find an adapter to use" end end
# File lib/turbostreamer.rb, line 21 def self.encode(options = {}, &block) new(options, &block).target! end
# File lib/turbostreamer.rb, line 244 def self.get_encoder(mime, key) require "turbostreamer/encoders/#{key}" Object.const_get("TurboStreamer::#{ENCODERS[mime][key]}Encoder") end
Same as the instance method key_format
! except sets the default.
# File lib/turbostreamer.rb, line 223 def self.key_format(*args) @@key_formatter = KeyFormatter.new(*args) end
# File lib/turbostreamer.rb, line 227 def self.key_formatter=(formatter) @@key_formatter = formatter end
# File lib/turbostreamer.rb, line 25 def initialize(options = {}) @output_buffer = options[:output_buffer] || ::StringIO.new if options[:encoder].is_a?(Symbol) @encoder = TurboStreamer.get_encoder(options[:mime] || :json, options[:encoder]) @encoder_options = @@encoder_options[options[:encoder]] elsif options[:encoder].nil? @encoder = TurboStreamer.default_encoder_for(options[:mime] || :json) if encoder_symbol = ENCODERS[options[:mime] || :json].find { |k, v| v == @encoder.name.delete_prefix('TurboStreamer::').delete_suffix('Encoder') }&.first @encoder_options = @@encoder_options[encoder_symbol] else @encoder_options = {} end else @encoder = options[:encoder] @encoder_options = {} end @encoder = @encoder.new(@output_buffer, @encoder_options) @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil } yield self if ::Kernel.block_given? end
# File lib/turbostreamer.rb, line 231 def self.set_default_encoder(mime, encoder, default_options={}) if encoder.is_a?(Symbol) @@default_encoders[mime] = get_encoder(mime, encoder) else @@default_encoders[mime] = encoder end @@encoder_options[encoder] = default_options end
# File lib/turbostreamer.rb, line 240 def self.set_default_encoder_options(encoder, options) @@encoder_options[encoder] = options end
Public Instance Methods
# File lib/turbostreamer.rb, line 270 def _extract_collection(collection, *attributes, &block) if collection.nil? # noop elsif block collection.each do |element| _scope{ yield element } end elsif attributes.any? collection.each { |element| pluck!(element, *attributes) } else collection.each { |element| value!(element) } end end
Turns the current element into an array and iterates over the passed collection, adding each iteration as an element of the resulting array.
Example:
json.array!(@people) do |person| json.name person.name json.age calculate_age(person.birthday) end [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]
It's generally only needed to use this method for top-level arrays. If you have named arrays, you can do:
json.people(@people) do |person| json.name person.name json.age calculate_age(person.birthday) end { "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] }
If you omit the block then you can set the top level array directly:
json.array! [1, 2, 3] [1,2,3]
# File lib/turbostreamer.rb, line 131 def array!(collection = BLANK, *attributes, &block) @encoder.array_open if _blank?(collection) _scope(&block) if block else _extract_collection(collection, *attributes, &block) end @encoder.array_close end
Turns the current element into an array and yields a builder to add a hash.
Example:
json.comments do json.child! { json.content "hello" } json.child! { json.content "world" } end { "comments": [ { "content": "hello" }, { "content": "world" } ]}
More commonly, you'd use the combined iterator, though:
json.comments(@post.comments) do |comment| json.content comment.formatted_content end
# File lib/turbostreamer.rb, line 305 def child!(value = BLANK, *args, &block) if block if _eachable_arguments?(value, *args) # json.child! comments { |c| ... } _scope { array!(value, &block) } else # json.child! { ... } # [...] _scope(&block) end elsif args.empty? value!(value) elsif _eachable_arguments?(value, *args) _scope{ array!(value, *args) } else object!{ extract!(value, *args) } end end
Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
Example:
@person = Struct.new(:name, :age).new('David', 32) or you can utilize a Hash @person = { name: 'David', age: 32 } json.extract! @person, :name, :age { "name": David", "age": 32 }, { "name": Jamie", "age": 31 }
# File lib/turbostreamer.rb, line 96 def extract!(object, *attributes) if ::Hash === object attributes.each{ |key| _set_value key, object.fetch(key) } else attributes.each{ |key| _set_value key, object.public_send(key) } end end
Inject a valid JSON string into the current
# File lib/turbostreamer.rb, line 285 def inject!(json_text) @encoder.inject(json_text) end
# File lib/turbostreamer.rb, line 48 def key!(key) @encoder.key(_key(key)) end
Specifies formatting to be applied to the key. Passing in a name of a function will cause that function to be called on the key. So :upcase will upper case the key. You can also pass in lambdas for more complex transformations.
Example:
json.key_format! :upcase json.author do json.name "David" json.age 32 end { "AUTHOR": { "NAME": "David", "AGE": 32 } }
You can pass parameters to the method using a hash pair.
json.key_format! camelize: :lower json.first_name "David" { "firstName": "David" }
Lambdas can also be used.
json.key_format! ->(key){ "_" + key } json.first_name "David" { "_first_name": "David" }
# File lib/turbostreamer.rb, line 218 def key_format!(*args) @key_formatter = KeyFormatter.new(*args) end
# File lib/turbostreamer.rb, line 171 def merge!(hash_or_array) if ::Array === hash_or_array hash_or_array.each do |array_element| value!(array_element) end elsif ::Hash === hash_or_array hash_or_array.each_pair do |key, value| key!(key) value!(value) end else raise Errors::MergeError.build(hash_or_array) end end
# File lib/turbostreamer.rb, line 56 def object!(&block) @encoder.map_open _scope { block.call } if block @encoder.map_close end
Extracts the mentioned attributes or hash elements from the passed object and turns them into a JSON object.
Example:
@person = Struct.new(:name, :age).new('David', 32) or you can utilize a Hash @person = { name: 'David', age: 32 } json.pluck! @person, :name, :age { "name": David", "age": 32 }
# File lib/turbostreamer.rb, line 76 def pluck!(object, *attributes) object! do extract!(object, *attributes) end end
# File lib/turbostreamer.rb, line 143 def set!(key, value = BLANK, *args, &block) key!(key) if block if !_blank?(value) # json.comments @post.comments { |comment| ... } # { "comments": [ { ... }, { ... } ] } _scope { array!(value, &block) } else # json.comments { ... } # { "comments": ... } _scope(&block) end elsif args.empty? # json.age 32 # { "age": 32 } value!(value) elsif _eachable_arguments?(value, *args) # json.comments @post.comments, :content, :created_at # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] } _scope{ array!(value, *args) } else # json.author @post.creator, :name, :email_address # { "author": { "name": "David", "email_address": "david@thinking.com" } } object!{ extract!(value, *args) } end end
Encodes the current builder as JSON.
# File lib/turbostreamer.rb, line 326 def target! @encoder.flush if @encoder.output.is_a?(::StringIO) @encoder.output.string else @encoder.output end end
# File lib/turbostreamer.rb, line 52 def value!(value) @encoder.value(value) end
Private Instance Methods
# File lib/turbostreamer.rb, line 367 def _blank?(value=@attributes) BLANK == value end
# File lib/turbostreamer.rb, line 352 def _capture(to=nil, &block) @encoder.capture(to, &block) end
# File lib/turbostreamer.rb, line 363 def _eachable_arguments?(value, *args) value.respond_to?(:each) && !value.is_a?(Hash) end
# File lib/turbostreamer.rb, line 343 def _key(key) @key_formatter ? @key_formatter.format(key) : key.to_s end
# File lib/turbostreamer.rb, line 356 def _scope parent_formatter = @key_formatter yield ensure @key_formatter = parent_formatter end
# File lib/turbostreamer.rb, line 347 def _set_value(key, value) return if _blank?(value) _write key, value end
# File lib/turbostreamer.rb, line 338 def _write(key, value) @encoder.key(_key(key)) @encoder.value(value) end