LiquidStream
This library does two things:
1) Allows chaining of Liquid objects with a clean DSL, which allows a more Ruby-like way to traverse Liquid objects. For example:
{% for post in posts.published.popular do %}
{{ post.name }}
{% endfor %}
2) Mimic accepting of arguments on drops
{{ image.resize_to["240x240#"].url }}
{{ images["23"].url }}
Installation
Add this line to your application's Gemfile:
gem 'liquid_stream'
And then execute:
$ bundle
Or install it yourself as:
$ gem install liquid_stream
Usage
Create a stream that represents one post:
class PostStream < LiquidStream::Stream
stream :name
end
Create a stream collection that represents a collection of posts:
class PostsStream < LiquidStream::Streams
stream :published
stream :popular
end
posts = user.posts
posts_stream = PostsStream.new(posts)
Liquid::Template.parse("liquid here").render('posts' => posts_stream)
"Accepting" Arguments
Given:
class ImageStream < LiquidStream::Stream
stream :process, as: :image do |command|
source.process command
end
stream :url
end
image = Image.find(2323)
image_stream = ImageStream.new(image)
Then, in Liquid:
{{image_stream.process["200x200"].process["grayscale"].url | image_tag}}
Stream Context
LiquidStream has a notion of context too. To avoid confusion with Liquid's context, let's call it "stream context". The reason there's a stream context is so that if you have a need to share information within a chained stream, then you need to pass it as a hash. I found this useful when the I needed the streams to know about which controller it was being used:
class PostsController < ApplicationController
def show
post = Post.find(params[:id])
post_stream = PostStream.new(post, controller: self)
Liquid::Template.parse("{{post.blog.children.first.url}}").render('posts' => post_stream)
end
end
class PostStream < LiquidStream::Stream
include Rails.application.helpers.url_helpers
def url
if controller.request.fullpath =~ /^preview/
polymorphic_path :preview, source
else
polymorphic_path source
end
end
private
def controller
stream_context[:controller]
end
end
It's a very specific use-case, but this allows you to render the links to other posts a different way if the person viewing is viewing the post from /preview/posts/:id
compared to what is rendered when in /posts/:id
. If you find other uses please fork this repo and add it to this readme.
Stream is a Liquid::Drop
A stream is a drop - with extra stuff added on to it.
Stream carefully
You may not want to expose something that will make it easy for a user to break your system. For example, let's say you have 2 million posts, then you won't want to expose all of those posts through a stream:
posts = Post.scoped # ActiveRecord's scoped returns a lazily executed Arel. If you call #all or #to_a on this, you'll get 2 million records
posts_stream = PostsStream.new(posts)
posts_stream.to_a # boom!
Stream/Streams Source
Singular Stream
and collection Streams
both use the term source. This is the object that is wrapped by the stream. For collection Streams
, source acts a little differently. The reason for this is best shown by the following:
s = PostsStream.new
s.source # nil
PostsStream.default_source = Post.all
s = PostsStream.new
s.source # Post.all
s = PostsStream.new(Post.popular)
s.source # Post.popular
As you can see, you may want the source of a collection stream to be different things, or default to something if none is given.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
Thanks
Check out the awesome contributors.