Class: TurboStreamer
- Inherits:
-
Object
- Object
- TurboStreamer
- Defined in:
- lib/turbostreamer/handler.rb,
lib/turbostreamer.rb,
lib/turbostreamer/errors.rb,
lib/turbostreamer/railtie.rb,
lib/turbostreamer/version.rb,
lib/turbostreamer/encoders/oj.rb,
lib/turbostreamer/encoders/wankel.rb,
lib/turbostreamer/dependency_tracker.rb
Overview
This module makes TurboStreamer work with Rails using the template handler API.
Direct Known Subclasses
Defined Under Namespace
Modules: DependencyTrackerMethods, Errors Classes: Handler, KeyFormatter, OjEncoder, Railtie, Template, WankelEncoder
Constant Summary collapse
- BLANK =
::Object.new
- ENCODERS =
{ json: {oj: 'Oj', wankel: 'Wankel'}, msgpack: {msgpack: 'MessagePack'} }
- VERSION =
'1.11.0'
- DependencyTracker =
Class.new(dependency_tracker::ERBTracker)
- @@default_encoders =
{}
- @@encoder_options =
Hash.new { |h, k| h[k] = {} }
- @@key_formatter =
nil
Class Method Summary collapse
- .default_encoder_for(mime) ⇒ Object
- .encode(options = {}, &block) ⇒ Object
- .get_encoder(mime, key) ⇒ Object
- .has_default_encoder_options?(encoder) ⇒ Boolean
-
.key_format(*args) ⇒ Object
Same as the instance method key_format! except sets the default.
- .key_formatter=(formatter) ⇒ Object
- .set_default_encoder(mime, encoder, default_options = nil) ⇒ Object
- .set_default_encoder_options(encoder, options) ⇒ Object
Instance Method Summary collapse
- #_extract_collection(collection, *attributes, &block) ⇒ Object
-
#array!(collection = BLANK, *attributes, &block) ⇒ Object
Turns the current element into an array and iterates over the passed collection, adding each iteration as an element of the resulting array.
-
#child!(value = BLANK, *args, &block) ⇒ Object
Turns the current element into an array and yields a builder to add a hash.
-
#extract!(object, *attributes) ⇒ Object
Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
-
#initialize(options = {}) {|_self| ... } ⇒ TurboStreamer
constructor
A new instance of TurboStreamer.
-
#inject!(json_text) ⇒ Object
Inject a valid JSON string into the current.
- #key!(key) ⇒ Object
-
#key_format!(*args) ⇒ Object
Specifies formatting to be applied to the key.
- #merge!(hash_or_array) ⇒ Object
- #object!(&block) ⇒ Object
-
#pluck!(object, *attributes) ⇒ Object
Extracts the mentioned attributes or hash elements from the passed object and turns them into a JSON object.
- #set!(key, value = BLANK, *args, &block) ⇒ Object (also: #method_missing)
-
#target! ⇒ Object
Encodes the current builder as JSON.
- #value!(value) ⇒ Object
Constructor Details
#initialize(options = {}) {|_self| ... } ⇒ TurboStreamer
Returns a new instance of TurboStreamer.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/turbostreamer.rb', line 28 def initialize( = {}) @output_buffer = [:output_buffer] || ::StringIO.new if [:encoder].is_a?(Symbol) @encoder = TurboStreamer.get_encoder([:mime] || :json, [:encoder]) @encoder_options = @@encoder_options[[:encoder]] elsif [:encoder].nil? @encoder = TurboStreamer.default_encoder_for([:mime] || :json) if encoder_symbol = ENCODERS[[: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 = [:encoder] @encoder_options = {} end @encoder = @encoder.new(@output_buffer, @encoder_options) @key_formatter = .fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil } yield self if ::Kernel.block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing ⇒ Object (private)
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/turbostreamer.rb', line 189 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": "[email protected]" } } object!{ extract!(value, *args) } end end |
Class Method Details
.default_encoder_for(mime) ⇒ Object
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/turbostreamer.rb', line 257 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) ⇒ Object
24 25 26 |
# File 'lib/turbostreamer.rb', line 24 def self.encode( = {}, &block) new(, &block).target! end |
.get_encoder(mime, key) ⇒ Object
252 253 254 255 |
# File 'lib/turbostreamer.rb', line 252 def self.get_encoder(mime, key) require "turbostreamer/encoders/#{key}" Object.const_get("TurboStreamer::#{ENCODERS[mime][key]}Encoder") end |
.has_default_encoder_options?(encoder) ⇒ Boolean
248 249 250 |
# File 'lib/turbostreamer.rb', line 248 def self.(encoder) @@encoder_options.has_key?(encoder) end |
.key_format(*args) ⇒ Object
Same as the instance method key_format! except sets the default.
226 227 228 |
# File 'lib/turbostreamer.rb', line 226 def self.key_format(*args) @@key_formatter = KeyFormatter.new(*args) end |
.key_formatter=(formatter) ⇒ Object
230 231 232 |
# File 'lib/turbostreamer.rb', line 230 def self.key_formatter=(formatter) @@key_formatter = formatter end |
.set_default_encoder(mime, encoder, default_options = nil) ⇒ Object
234 235 236 237 238 239 240 241 242 |
# File 'lib/turbostreamer.rb', line 234 def self.set_default_encoder(mime, encoder, =nil) @@default_encoders[mime] = if encoder.is_a?(Symbol) get_encoder(mime, encoder) else encoder end @@encoder_options[encoder] = if end |
.set_default_encoder_options(encoder, options) ⇒ Object
244 245 246 |
# File 'lib/turbostreamer.rb', line 244 def self.(encoder, ) @@encoder_options[encoder] = end |
Instance Method Details
#_extract_collection(collection, *attributes, &block) ⇒ Object
278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/turbostreamer.rb', line 278 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) ⇒ Object
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]
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/turbostreamer.rb', line 134 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) ⇒ Object
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
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/turbostreamer.rb', line 313 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) ⇒ Object
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 }
99 100 101 102 103 104 105 |
# File 'lib/turbostreamer.rb', line 99 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) ⇒ Object
Inject a valid JSON string into the current
293 294 295 |
# File 'lib/turbostreamer.rb', line 293 def inject!(json_text) @encoder.inject(json_text) end |
#key!(key) ⇒ Object
51 52 53 |
# File 'lib/turbostreamer.rb', line 51 def key!(key) @encoder.key(_key(key)) end |
#key_format!(*args) ⇒ Object
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. 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" }
221 222 223 |
# File 'lib/turbostreamer.rb', line 221 def key_format!(*args) @key_formatter = KeyFormatter.new(*args) end |
#merge!(hash_or_array) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/turbostreamer.rb', line 174 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) ⇒ Object
59 60 61 62 63 |
# File 'lib/turbostreamer.rb', line 59 def object!(&block) @encoder.map_open _scope { block.call } if block @encoder.map_close end |
#pluck!(object, *attributes) ⇒ Object
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 }
79 80 81 82 83 |
# File 'lib/turbostreamer.rb', line 79 def pluck!(object, *attributes) object! do extract!(object, *attributes) end end |
#set!(key, value = BLANK, *args, &block) ⇒ Object Also known as: method_missing
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/turbostreamer.rb', line 146 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": "[email protected]" } } object!{ extract!(value, *args) } end end |
#target! ⇒ Object
Encodes the current builder as JSON.
334 335 336 337 338 339 340 341 342 |
# File 'lib/turbostreamer.rb', line 334 def target! @encoder.flush if @encoder.output.is_a?(::StringIO) @encoder.output.string else @encoder.output end end |
#value!(value) ⇒ Object
55 56 57 |
# File 'lib/turbostreamer.rb', line 55 def value!(value) @encoder.value(value) end |