class TurboStreamer

This module makes TurboStreamer work with Rails using the template handler API.

Constants

BLANK
DependencyTracker
ENCODERS
VERSION

Public Class Methods

default_encoder_for(mime) click to toggle source
# 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
encode(options = {}, &block) click to toggle source
# File lib/turbostreamer.rb, line 21
def self.encode(options = {}, &block)
  new(options, &block).target!
end
get_encoder(mime, key) click to toggle source
# 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
key_format(*args) click to toggle source

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
key_formatter=(formatter) click to toggle source
# File lib/turbostreamer.rb, line 227
def self.key_formatter=(formatter)
  @@key_formatter = formatter
end
new(options = {}) { |self| ... } click to toggle source
# 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
set_default_encoder(mime, encoder, default_options={}) click to toggle source
# 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
set_default_encoder_options(encoder, options) click to toggle source
# File lib/turbostreamer.rb, line 240
def self.set_default_encoder_options(encoder, options)
  @@encoder_options[encoder] = options
end

Public Instance Methods

_extract_collection(collection, *attributes) { |element| ... } click to toggle source
# 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
array!(collection = BLANK, *attributes, &block) click to toggle source

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
child!(value = BLANK, *args, &block) click to toggle source

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
extract!(object, *attributes) click to toggle source

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!(json_text) click to toggle source

Inject a valid JSON string into the current

# File lib/turbostreamer.rb, line 285
def inject!(json_text)
  @encoder.inject(json_text)
end
key!(key) click to toggle source
# File lib/turbostreamer.rb, line 48
def key!(key)
  @encoder.key(_key(key))
end
key_format!(*args) click to toggle source

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
merge!(hash_or_array) click to toggle source
# 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
object!(&block) click to toggle source
# File lib/turbostreamer.rb, line 56
def object!(&block)
  @encoder.map_open
  _scope { block.call } if block
  @encoder.map_close
end
pluck!(object, *attributes) click to toggle source

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
set!(key, value = BLANK, *args, &block) click to toggle source
# 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
Also aliased as: method_missing
target!() click to toggle source

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
value!(value) click to toggle source
# File lib/turbostreamer.rb, line 52
def value!(value)
  @encoder.value(value)
end

Private Instance Methods

_blank?(value=@attributes) click to toggle source
# File lib/turbostreamer.rb, line 367
def _blank?(value=@attributes)
  BLANK == value
end
_capture(to=nil, &block) click to toggle source
# File lib/turbostreamer.rb, line 352
def _capture(to=nil, &block)
  @encoder.capture(to, &block)
end
_eachable_arguments?(value, *args) click to toggle source
# File lib/turbostreamer.rb, line 363
def _eachable_arguments?(value, *args)
  value.respond_to?(:each) && !value.is_a?(Hash)
end
_key(key) click to toggle source
# File lib/turbostreamer.rb, line 343
def _key(key)
  @key_formatter ? @key_formatter.format(key) : key.to_s
end
_scope() { || ... } click to toggle source
# File lib/turbostreamer.rb, line 356
def _scope
  parent_formatter = @key_formatter
  yield
ensure
  @key_formatter = parent_formatter
end
_set_value(key, value) click to toggle source
# File lib/turbostreamer.rb, line 347
def _set_value(key, value)
  return if _blank?(value)
  _write key, value
end
_write(key, value) click to toggle source
# File lib/turbostreamer.rb, line 338
def _write(key, value)
  @encoder.key(_key(key))
  @encoder.value(value)
end
method_missing(key, value = BLANK, *args, &block)
Alias for: set!