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/key_formatter.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.8.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
-
.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 = {}) ⇒ 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.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/turbostreamer.rb', line 25 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)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/turbostreamer.rb', line 186 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
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# 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) ⇒ Object
21 22 23 |
# File 'lib/turbostreamer.rb', line 21 def self.encode( = {}, &block) new(, &block).target! end |
.get_encoder(mime, key) ⇒ Object
244 245 246 247 |
# 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) ⇒ Object
Same as the instance method key_format! except sets the default.
223 224 225 |
# File 'lib/turbostreamer.rb', line 223 def self.key_format(*args) @@key_formatter = KeyFormatter.new(*args) end |
.key_formatter=(formatter) ⇒ Object
227 228 229 |
# File 'lib/turbostreamer.rb', line 227 def self.key_formatter=(formatter) @@key_formatter = formatter end |
.set_default_encoder(mime, encoder, default_options = {}) ⇒ Object
231 232 233 234 235 236 237 238 |
# File 'lib/turbostreamer.rb', line 231 def self.set_default_encoder(mime, encoder, ={}) if encoder.is_a?(Symbol) @@default_encoders[mime] = get_encoder(mime, encoder) else @@default_encoders[mime] = encoder end @@encoder_options[encoder] = end |
.set_default_encoder_options(encoder, options) ⇒ Object
240 241 242 |
# File 'lib/turbostreamer.rb', line 240 def self.(encoder, ) @@encoder_options[encoder] = end |
Instance Method Details
#_extract_collection(collection, *attributes, &block) ⇒ Object
270 271 272 273 274 275 276 277 278 279 280 281 282 |
# 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) ⇒ 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]
131 132 133 134 135 136 137 138 139 140 141 |
# 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) ⇒ 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
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# 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) ⇒ 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 }
96 97 98 99 100 101 102 |
# 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) ⇒ Object
Inject a valid JSON string into the current
285 286 287 |
# File 'lib/turbostreamer.rb', line 285 def inject!(json_text) @encoder.inject(json_text) end |
#key!(key) ⇒ Object
48 49 50 |
# File 'lib/turbostreamer.rb', line 48 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" }
218 219 220 |
# File 'lib/turbostreamer.rb', line 218 def key_format!(*args) @key_formatter = KeyFormatter.new(*args) end |
#merge!(hash_or_array) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# 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) ⇒ Object
56 57 58 59 60 |
# File 'lib/turbostreamer.rb', line 56 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 }
76 77 78 79 80 |
# File 'lib/turbostreamer.rb', line 76 def pluck!(object, *attributes) object! do extract!(object, *attributes) end end |
#set!(key, value = BLANK, *args, &block) ⇒ Object Also known as: method_missing
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# 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": "[email protected]" } } object!{ extract!(value, *args) } end end |
#target! ⇒ Object
Encodes the current builder as JSON.
326 327 328 329 330 331 332 333 334 |
# 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) ⇒ Object
52 53 54 |
# File 'lib/turbostreamer.rb', line 52 def value!(value) @encoder.value(value) end |