jbuilder-2.7.0/ 0000755 0000041 0000041 00000000000 13273321662 013355 5 ustar www-data www-data jbuilder-2.7.0/.travis.yml 0000644 0000041 0000041 00000002630 13273321662 015467 0 ustar www-data www-data language: ruby
sudo: false
cache: bundler
rvm:
- 1.9
- 2.0
- 2.1
- 2.2.5
- 2.3.1
- 2.4.0
- ruby-head
- jruby-19mode
- rbx
gemfile:
- gemfiles/rails_3_0.gemfile
- gemfiles/rails_3_1.gemfile
- gemfiles/rails_3_2.gemfile
- gemfiles/rails_4_0.gemfile
- gemfiles/rails_4_1.gemfile
- gemfiles/rails_4_2.gemfile
- gemfiles/rails_5_0.gemfile
- gemfiles/rails_5_1.gemfile
matrix:
allow_failures:
- rvm: jruby-19mode
- rvm: rbx
- rvm: ruby-head
fast_finish: true
exclude:
- rvm: 1.9
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 1.9
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 2.0
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 2.0
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 2.1
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 2.1
gemfile: gemfiles/rails_5_1.gemfile
- rvm: jruby-19mode
gemfile: gemfiles/rails_5_0.gemfile
- rvm: jruby-19mode
gemfile: gemfiles/rails_5_1.gemfile
- rvm: rbx
gemfile: gemfiles/rails_5_0.gemfile
- rvm: rbx
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 2.4.0
gemfile: gemfiles/rails_3_0.gemfile
- rvm: 2.4.0
gemfile: gemfiles/rails_3_1.gemfile
- rvm: 2.4.0
gemfile: gemfiles/rails_3_2.gemfile
- rvm: 2.4.0
gemfile: gemfiles/rails_4_0.gemfile
- rvm: 2.4.0
gemfile: gemfiles/rails_4_1.gemfile
notifications:
email: false
jbuilder-2.7.0/test/ 0000755 0000041 0000041 00000000000 13273321662 014334 5 ustar www-data www-data jbuilder-2.7.0/test/jbuilder_template_test.rb 0000644 0000041 0000041 00000027317 13273321662 021425 0 ustar www-data www-data require "test_helper"
require "mocha/setup"
require "active_model"
require "action_view"
require "action_view/testing/resolvers"
require "active_support/cache"
require "jbuilder/jbuilder_template"
BLOG_POST_PARTIAL = <<-JBUILDER
json.extract! blog_post, :id, :body
json.author do
first_name, last_name = blog_post.author_name.split(nil, 2)
json.first_name first_name
json.last_name last_name
end
JBUILDER
COLLECTION_PARTIAL = <<-JBUILDER
json.extract! collection, :id, :name
JBUILDER
RACER_PARTIAL = <<-JBUILDER
json.extract! racer, :id, :name
JBUILDER
class Racer
extend ActiveModel::Naming
include ActiveModel::Conversion
def initialize(id, name)
@id, @name = id, name
end
attr_reader :id, :name
end
BlogPost = Struct.new(:id, :body, :author_name)
Collection = Struct.new(:id, :name)
blog_authors = [ "David Heinemeier Hansson", "Pavel Pravosud" ].cycle
BLOG_POST_COLLECTION = Array.new(10){ |i| BlogPost.new(i+1, "post body #{i+1}", blog_authors.next) }
COLLECTION_COLLECTION = Array.new(5){ |i| Collection.new(i+1, "collection #{i+1}") }
ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
PARTIALS = {
"_partial.json.jbuilder" => "foo ||= 'hello'; json.content foo",
"_blog_post.json.jbuilder" => BLOG_POST_PARTIAL,
"racers/_racer.json.jbuilder" => RACER_PARTIAL,
"_collection.json.jbuilder" => COLLECTION_PARTIAL
}
module Rails
def self.cache
@cache ||= ActiveSupport::Cache::MemoryStore.new
end
end
class JbuilderTemplateTest < ActionView::TestCase
setup do
@context = self
Rails.cache.clear
end
def jbuild(source, options = {})
@rendered = []
partials = options.fetch(:partials, PARTIALS).clone
partials["test.json.jbuilder"] = source
resolver = ActionView::FixtureResolver.new(partials)
lookup_context.view_paths = [resolver]
template = ActionView::Template.new(source, "test", JbuilderHandler, virtual_path: "test")
json = template.render(self, {}).strip
MultiJson.load(json)
end
def undef_context_methods(*names)
self.class_eval do
names.each do |name|
undef_method name.to_sym if method_defined?(name.to_sym)
end
end
end
def assert_collection_rendered(result, context = nil)
result = result.fetch(context) if context
assert_equal 10, result.length
assert_equal Array, result.class
assert_equal "post body 5", result[4]["body"]
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
assert_equal "Pavel", result[5]["author"]["first_name"]
end
test "rendering" do
result = jbuild(<<-JBUILDER)
json.content "hello"
JBUILDER
assert_equal "hello", result["content"]
end
test "key_format! with parameter" do
result = jbuild(<<-JBUILDER)
json.key_format! camelize: [:lower]
json.camel_style "for JS"
JBUILDER
assert_equal ["camelStyle"], result.keys
end
test "key_format! propagates to child elements" do
result = jbuild(<<-JBUILDER)
json.key_format! :upcase
json.level1 "one"
json.level2 do
json.value "two"
end
JBUILDER
assert_equal "one", result["LEVEL1"]
assert_equal "two", result["LEVEL2"]["VALUE"]
end
test "partial! renders partial" do
result = jbuild(<<-JBUILDER)
json.partial! "partial"
JBUILDER
assert_equal "hello", result["content"]
end
test "partial! + locals via :locals option" do
result = jbuild(<<-JBUILDER)
json.partial! "partial", locals: { foo: "howdy" }
JBUILDER
assert_equal "howdy", result["content"]
end
test "partial! + locals without :locals key" do
result = jbuild(<<-JBUILDER)
json.partial! "partial", foo: "goodbye"
JBUILDER
assert_equal "goodbye", result["content"]
end
test "partial! renders collections" do
result = jbuild(<<-JBUILDER)
json.partial! "blog_post", collection: BLOG_POST_COLLECTION, as: :blog_post
JBUILDER
assert_collection_rendered result
end
test "partial! renders collections when as argument is a string" do
result = jbuild(<<-JBUILDER)
json.partial! "blog_post", collection: BLOG_POST_COLLECTION, as: "blog_post"
JBUILDER
assert_collection_rendered result
end
test "partial! renders collections as collections" do
result = jbuild(<<-JBUILDER)
json.partial! "collection", collection: COLLECTION_COLLECTION, as: :collection
JBUILDER
assert_equal 5, result.length
end
test "partial! renders as empty array for nil-collection" do
result = jbuild(<<-JBUILDER)
json.partial! "blog_post", collection: nil, as: :blog_post
JBUILDER
assert_equal [], result
end
test "partial! renders collection (alt. syntax)" do
result = jbuild(<<-JBUILDER)
json.partial! partial: "blog_post", collection: BLOG_POST_COLLECTION, as: :blog_post
JBUILDER
assert_collection_rendered result
end
test "partial! renders as empty array for nil-collection (alt. syntax)" do
result = jbuild(<<-JBUILDER)
json.partial! partial: "blog_post", collection: nil, as: :blog_post
JBUILDER
assert_equal [], result
end
test "render array of partials" do
result = jbuild(<<-JBUILDER)
json.array! BLOG_POST_COLLECTION, partial: "blog_post", as: :blog_post
JBUILDER
assert_collection_rendered result
end
test "render array of partials as empty array with nil-collection" do
result = jbuild(<<-JBUILDER)
json.array! nil, partial: "blog_post", as: :blog_post
JBUILDER
assert_equal [], result
end
test "render array of partials as a value" do
result = jbuild(<<-JBUILDER)
json.posts BLOG_POST_COLLECTION, partial: "blog_post", as: :blog_post
JBUILDER
assert_collection_rendered result, "posts"
end
test "render as empty array if partials as a nil value" do
result = jbuild <<-JBUILDER
json.posts nil, partial: "blog_post", as: :blog_post
JBUILDER
assert_equal [], result["posts"]
end
test "cache an empty block" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
jbuild <<-JBUILDER
json.cache! "nothing" do
end
JBUILDER
result = nil
assert_nothing_raised do
result = jbuild(<<-JBUILDER)
json.foo "bar"
json.cache! "nothing" do
end
JBUILDER
end
assert_equal "bar", result["foo"]
end
test "fragment caching a JSON object" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.name "Cache"
end
JBUILDER
result = jbuild(<<-JBUILDER)
json.cache! "cachekey" do
json.name "Miss"
end
JBUILDER
assert_equal "Cache", result["name"]
end
test "conditionally fragment caching a JSON object" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
jbuild <<-JBUILDER
json.cache_if! true, "cachekey" do
json.test1 "Cache"
end
json.cache_if! false, "cachekey" do
json.test2 "Cache"
end
JBUILDER
result = jbuild(<<-JBUILDER)
json.cache_if! true, "cachekey" do
json.test1 "Miss"
end
json.cache_if! false, "cachekey" do
json.test2 "Miss"
end
JBUILDER
assert_equal "Cache", result["test1"]
assert_equal "Miss", result["test2"]
end
test "fragment caching deserializes an array" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.array! %w[a b c]
end
JBUILDER
result = jbuild(<<-JBUILDER)
json.cache! "cachekey" do
json.array! %w[1 2 3]
end
JBUILDER
assert_equal %w[a b c], result
end
test "fragment caching works with current cache digests" do
undef_context_methods :fragment_name_with_digest
@context.expects :cache_fragment_name
ActiveSupport::Cache.expects :expand_cache_key
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.name "Cache"
end
JBUILDER
end
test "fragment caching uses fragment_cache_key" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
@context.expects(:fragment_cache_key).with("cachekey")
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.name "Cache"
end
JBUILDER
end
test "fragment caching instrumentation" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
payloads = {}
ActiveSupport::Notifications.subscribe("read_fragment.action_controller") { |*args| payloads[:read_fragment] = args.last }
ActiveSupport::Notifications.subscribe("write_fragment.action_controller") { |*args| payloads[:write_fragment] = args.last }
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.name "Cache"
end
JBUILDER
assert_equal "jbuilder/cachekey", payloads[:read_fragment][:key]
assert_equal "jbuilder/cachekey", payloads[:write_fragment][:key]
end
test "current cache digest option accepts options" do
undef_context_methods :fragment_name_with_digest
@context.expects(:cache_fragment_name).with("cachekey", skip_digest: true)
ActiveSupport::Cache.expects :expand_cache_key
jbuild <<-JBUILDER
json.cache! "cachekey", skip_digest: true do
json.name "Cache"
end
JBUILDER
end
test "fragment caching accepts expires_in option" do
undef_context_methods :fragment_name_with_digest
@context.expects(:cache_fragment_name).with("cachekey", {})
jbuild <<-JBUILDER
json.cache! "cachekey", expires_in: 1.minute do
json.name "Cache"
end
JBUILDER
end
test "caching root structure" do
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
cache_miss_result = jbuild <<-JBUILDER
json.cache_root! "cachekey" do
json.name "Miss"
end
JBUILDER
cache_hit_result = jbuild <<-JBUILDER
json.cache_root! "cachekey" do
json.name "Hit"
end
JBUILDER
assert_equal cache_miss_result, cache_hit_result
end
test "failing to cache root after attributes have been defined" do
assert_raises ActionView::Template::Error, "cache_root! can't be used after JSON structures have been defined" do
jbuild <<-JBUILDER
json.name "Kaboom"
json.cache_root! "cachekey" do
json.name "Miss"
end
JBUILDER
end
end
test "does not perform caching when controller.perform_caching is false" do
controller.perform_caching = false
jbuild <<-JBUILDER
json.cache! "cachekey" do
json.name "Cache"
end
JBUILDER
assert_equal Rails.cache.inspect[/entries=(\d+)/, 1], "0"
end
test "invokes templates via params via set!" do
@post = BLOG_POST_COLLECTION.first
result = jbuild(<<-JBUILDER)
json.post @post, partial: "blog_post", as: :blog_post
JBUILDER
assert_equal 1, result["post"]["id"]
assert_equal "post body 1", result["post"]["body"]
assert_equal "David", result["post"]["author"]["first_name"]
end
test "invokes templates implicitly for ActiveModel objects" do
@racer = Racer.new(123, "Chris Harris")
result = jbuild(<<-JBUILDER)
json.partial! @racer
JBUILDER
assert_equal %w[id name], result.keys
assert_equal 123, result["id"]
assert_equal "Chris Harris", result["name"]
end
test "renders partial via set! with same name as HTML partial" do
partials = {
"_blog_post.html.erb" => "Hello!",
"_blog_post.json.jbuilder" => BLOG_POST_PARTIAL
}
@post = BLOG_POST_COLLECTION.first
result = jbuild(<<-JBUILDER, partials: partials)
json.post @post, partial: "blog_post", as: :blog_post
JBUILDER
assert_not_nil result["post"]
assert_equal 1, result["post"]["id"]
end
end
jbuilder-2.7.0/test/scaffold_api_controller_generator_test.rb 0000644 0000041 0000041 00000003537 13273321662 024653 0 ustar www-data www-data require 'test_helper'
require 'rails/generators/test_case'
require 'generators/rails/scaffold_controller_generator'
if Rails::VERSION::MAJOR > 4
class ScaffoldApiControllerGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::ScaffoldControllerGenerator
arguments %w(Post title body:text --api)
destination File.expand_path('../tmp', __FILE__)
setup :prepare_destination
test 'controller content' do
run_generator
assert_file 'app/controllers/posts_controller.rb' do |content|
assert_instance_method :index, content do |m|
assert_match %r{@posts = Post\.all}, m
end
assert_instance_method :show, content do |m|
assert m.blank?
end
assert_instance_method :create, content do |m|
assert_match %r{@post = Post\.new\(post_params\)}, m
assert_match %r{@post\.save}, m
assert_match %r{render :show, status: :created, location: @post}, m
assert_match %r{render json: @post\.errors, status: :unprocessable_entity}, m
end
assert_instance_method :update, content do |m|
assert_match %r{render :show, status: :ok, location: @post}, m
assert_match %r{render json: @post.errors, status: :unprocessable_entity}, m
end
assert_instance_method :destroy, content do |m|
assert_match %r{@post\.destroy}, m
end
assert_match %r{def post_params}, content
assert_match %r{params\.require\(:post\)\.permit\(:title, :body\)}, content
end
end
test 'dont use require and permit if there are no attributes' do
run_generator %w(Post --api)
assert_file 'app/controllers/posts_controller.rb' do |content|
assert_match %r{def post_params}, content
assert_match %r{params\.fetch\(:post, \{\}\)}, content
end
end
end
end
jbuilder-2.7.0/test/jbuilder_generator_test.rb 0000644 0000041 0000041 00000002213 13273321662 021564 0 ustar www-data www-data require 'test_helper'
require 'rails/generators/test_case'
require 'generators/rails/jbuilder_generator'
class JbuilderGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::JbuilderGenerator
arguments %w(Post title body:text password:digest)
destination File.expand_path('../tmp', __FILE__)
setup :prepare_destination
test 'views are generated' do
run_generator
%w(index show).each do |view|
assert_file "app/views/posts/#{view}.json.jbuilder"
end
assert_file "app/views/posts/_post.json.jbuilder"
end
test 'index content' do
run_generator
assert_file 'app/views/posts/index.json.jbuilder' do |content|
assert_match %r{json.array! @posts, partial: 'posts/post', as: :post}, content
end
assert_file 'app/views/posts/show.json.jbuilder' do |content|
assert_match %r{json.partial! \"posts/post\", post: @post}, content
end
assert_file 'app/views/posts/_post.json.jbuilder' do |content|
assert_match %r{json\.extract! post, :id, :title, :body}, content
assert_match %r{json\.url post_url\(post, format: :json\)}, content
end
end
end
jbuilder-2.7.0/test/jbuilder_dependency_tracker_test.rb 0000644 0000041 0000041 00000004050 13273321662 023430 0 ustar www-data www-data require 'test_helper'
require 'jbuilder/dependency_tracker'
class FakeTemplate
attr_reader :source, :handler
def initialize(source, handler = :jbuilder)
@source, @handler = source, handler
end
end
class JbuilderDependencyTrackerTest < ActiveSupport::TestCase
def make_tracker(name, source)
template = FakeTemplate.new(source)
Jbuilder::DependencyTracker.new(name, template)
end
def track_dependencies(source)
make_tracker('jbuilder_template', source).dependencies
end
test 'detects dependency via direct partial! call' do
dependencies = track_dependencies <<-RUBY
json.partial! 'path/to/partial', foo: bar
json.partial! 'path/to/another/partial', :fizz => buzz
RUBY
assert_equal %w[path/to/partial path/to/another/partial], dependencies
end
test 'detects dependency via direct partial! call with parens' do
dependencies = track_dependencies <<-RUBY
json.partial!("path/to/partial")
RUBY
assert_equal %w[path/to/partial], dependencies
end
test 'detects partial with options (1.9 style)' do
dependencies = track_dependencies <<-RUBY
json.partial! hello: 'world', partial: 'path/to/partial', foo: :bar
RUBY
assert_equal %w[path/to/partial], dependencies
end
test 'detects partial with options (1.8 style)' do
dependencies = track_dependencies <<-RUBY
json.partial! :hello => 'world', :partial => 'path/to/partial', :foo => :bar
RUBY
assert_equal %w[path/to/partial], dependencies
end
test 'detects partial in indirect collecton calls' do
dependencies = track_dependencies <<-RUBY
json.comments @post.comments, partial: 'comments/comment', as: :comment
RUBY
assert_equal %w[comments/comment], dependencies
end
test 'detects explicit depedency' do
dependencies = track_dependencies <<-RUBY
# Template Dependency: path/to/partial
json.foo 'bar'
RUBY
assert_equal %w[path/to/partial], dependencies
end
end
jbuilder-2.7.0/test/scaffold_controller_generator_test.rb 0000644 0000041 0000041 00000004756 13273321662 024026 0 ustar www-data www-data require 'test_helper'
require 'rails/generators/test_case'
require 'generators/rails/scaffold_controller_generator'
class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::ScaffoldControllerGenerator
arguments %w(Post title body:text)
destination File.expand_path('../tmp', __FILE__)
setup :prepare_destination
test 'controller content' do
run_generator
assert_file 'app/controllers/posts_controller.rb' do |content|
assert_instance_method :index, content do |m|
assert_match %r{@posts = Post\.all}, m
end
assert_instance_method :show, content do |m|
assert m.blank?
end
assert_instance_method :new, content do |m|
assert_match %r{@post = Post\.new}, m
end
assert_instance_method :edit, content do |m|
assert m.blank?
end
assert_instance_method :create, content do |m|
assert_match %r{@post = Post\.new\(post_params\)}, m
assert_match %r{@post\.save}, m
assert_match %r{format\.html \{ redirect_to @post, notice: 'Post was successfully created\.' \}}, m
assert_match %r{format\.json \{ render :show, status: :created, location: @post \}}, m
assert_match %r{format\.html \{ render :new \}}, m
assert_match %r{format\.json \{ render json: @post\.errors, status: :unprocessable_entity \}}, m
end
assert_instance_method :update, content do |m|
assert_match %r{format\.html \{ redirect_to @post, notice: 'Post was successfully updated\.' \}}, m
assert_match %r{format\.json \{ render :show, status: :ok, location: @post \}}, m
assert_match %r{format\.html \{ render :edit \}}, m
assert_match %r{format\.json \{ render json: @post.errors, status: :unprocessable_entity \}}, m
end
assert_instance_method :destroy, content do |m|
assert_match %r{@post\.destroy}, m
assert_match %r{format\.html \{ redirect_to posts_url, notice: 'Post was successfully destroyed\.' \}}, m
assert_match %r{format\.json \{ head :no_content \}}, m
end
assert_match %r{def post_params}, content
assert_match %r{params\.require\(:post\)\.permit\(:title, :body\)}, content
end
end
test 'dont use require and permit if there are no attributes' do
run_generator %w(Post)
assert_file 'app/controllers/posts_controller.rb' do |content|
assert_match %r{def post_params}, content
assert_match %r{params\.fetch\(:post, \{\}\)}, content
end
end
end
jbuilder-2.7.0/test/test_helper.rb 0000644 0000041 0000041 00000000414 13273321662 017176 0 ustar www-data www-data require "bundler/setup"
require "active_support"
require "rails/version"
if Rails::VERSION::STRING > "4.0"
require "active_support/testing/autorun"
else
require "test/unit"
end
if ActiveSupport.respond_to?(:test_order=)
ActiveSupport.test_order = :random
end
jbuilder-2.7.0/test/jbuilder_test.rb 0000644 0000041 0000041 00000041107 13273321662 017523 0 ustar www-data www-data require 'test_helper'
require 'active_support/inflector'
require 'jbuilder'
def jbuild(*args, &block)
Jbuilder.new(*args, &block).attributes!
end
Comment = Struct.new(:content, :id)
class NonEnumerable
def initialize(collection)
@collection = collection
end
delegate :map, :count, to: :@collection
end
class VeryBasicWrapper < BasicObject
def initialize(thing)
@thing = thing
end
def method_missing(name, *args, &block)
@thing.send name, *args, &block
end
end
# This is not Struct, because structs are Enumerable
class Person
attr_reader :name, :age
def initialize(name, age)
@name, @age = name, age
end
end
class RelationMock
include Enumerable
def each(&block)
[Person.new('Bob', 30), Person.new('Frank', 50)].each(&block)
end
def empty?
false
end
end
class JbuilderTest < ActiveSupport::TestCase
setup do
Jbuilder.send :class_variable_set, '@@key_formatter', nil
end
test 'single key' do
result = jbuild do |json|
json.content 'hello'
end
assert_equal 'hello', result['content']
end
test 'single key with false value' do
result = jbuild do |json|
json.content false
end
assert_equal false, result['content']
end
test 'single key with nil value' do
result = jbuild do |json|
json.content nil
end
assert result.has_key?('content')
assert_equal nil, result['content']
end
test 'multiple keys' do
result = jbuild do |json|
json.title 'hello'
json.content 'world'
end
assert_equal 'hello', result['title']
assert_equal 'world', result['content']
end
test 'extracting from object' do
person = Struct.new(:name, :age).new('David', 32)
result = jbuild do |json|
json.extract! person, :name, :age
end
assert_equal 'David', result['name']
assert_equal 32, result['age']
end
test 'extracting from object using call style for 1.9' do
person = Struct.new(:name, :age).new('David', 32)
result = jbuild do |json|
json.(person, :name, :age)
end
assert_equal 'David', result['name']
assert_equal 32, result['age']
end
test 'extracting from hash' do
person = {:name => 'Jim', :age => 34}
result = jbuild do |json|
json.extract! person, :name, :age
end
assert_equal 'Jim', result['name']
assert_equal 34, result['age']
end
test 'nesting single child with block' do
result = jbuild do |json|
json.author do
json.name 'David'
json.age 32
end
end
assert_equal 'David', result['author']['name']
assert_equal 32, result['author']['age']
end
test 'empty block handling' do
result = jbuild do |json|
json.foo 'bar'
json.author do
end
end
assert_equal 'bar', result['foo']
assert !result.key?('author')
end
test 'blocks are additive' do
result = jbuild do |json|
json.author do
json.name 'David'
end
json.author do
json.age 32
end
end
assert_equal 'David', result['author']['name']
assert_equal 32, result['author']['age']
end
test 'support merge! method' do
result = jbuild do |json|
json.merge! 'foo' => 'bar'
end
assert_equal 'bar', result['foo']
end
test 'support merge! method in a block' do
result = jbuild do |json|
json.author do
json.merge! 'name' => 'Pavel'
end
end
assert_equal 'Pavel', result['author']['name']
end
test 'blocks are additive via extract syntax' do
person = Person.new('Pavel', 27)
result = jbuild do |json|
json.author person, :age
json.author person, :name
end
assert_equal 'Pavel', result['author']['name']
assert_equal 27, result['author']['age']
end
test 'arrays are additive' do
result = jbuild do |json|
json.array! %w[foo]
json.array! %w[bar]
end
assert_equal %w[foo bar], result
end
test 'nesting multiple children with block' do
result = jbuild do |json|
json.comments do
json.child! { json.content 'hello' }
json.child! { json.content 'world' }
end
end
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'nesting single child with inline extract' do
person = Person.new('David', 32)
result = jbuild do |json|
json.author person, :name, :age
end
assert_equal 'David', result['author']['name']
assert_equal 32, result['author']['age']
end
test 'nesting multiple children from array' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.comments comments, :content
end
assert_equal ['content'], result['comments'].first.keys
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'nesting multiple children from array when child array is empty' do
comments = []
result = jbuild do |json|
json.name 'Parent'
json.comments comments, :content
end
assert_equal 'Parent', result['name']
assert_equal [], result['comments']
end
test 'nesting multiple children from array with inline loop' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.comments comments do |comment|
json.content comment.content
end
end
assert_equal ['content'], result['comments'].first.keys
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'handles nil-collections as empty arrays' do
result = jbuild do |json|
json.comments nil do |comment|
json.content comment.content
end
end
assert_equal [], result['comments']
end
test 'nesting multiple children from a non-Enumerable that responds to #map' do
comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
result = jbuild do |json|
json.comments comments, :content
end
assert_equal ['content'], result['comments'].first.keys
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'nesting multiple chilren from a non-Enumerable that responds to #map with inline loop' do
comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
result = jbuild do |json|
json.comments comments do |comment|
json.content comment.content
end
end
assert_equal ['content'], result['comments'].first.keys
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'array! casts array-like objects to array before merging' do
wrapped_array = VeryBasicWrapper.new(%w[foo bar])
result = jbuild do |json|
json.array! wrapped_array
end
assert_equal %w[foo bar], result
end
test 'nesting multiple children from array with inline loop on root' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.call(comments) do |comment|
json.content comment.content
end
end
assert_equal 'hello', result.first['content']
assert_equal 'world', result.second['content']
end
test 'array nested inside nested hash' do
result = jbuild do |json|
json.author do
json.name 'David'
json.age 32
json.comments do
json.child! { json.content 'hello' }
json.child! { json.content 'world' }
end
end
end
assert_equal 'hello', result['author']['comments'].first['content']
assert_equal 'world', result['author']['comments'].second['content']
end
test 'array nested inside array' do
result = jbuild do |json|
json.comments do
json.child! do
json.authors do
json.child! do
json.name 'david'
end
end
end
end
end
assert_equal 'david', result['comments'].first['authors'].first['name']
end
test 'directly set an array nested in another array' do
data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
result = jbuild do |json|
json.array! data do |object|
json.department object[:department]
json.names do
json.array! object[:names]
end
end
end
assert_equal 'David', result[0]['names'].last
assert !result[0].key?('not_in_json')
end
test 'nested jbuilder objects' do
to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
result = jbuild do |json|
json.value 'Test'
json.nested to_nest
end
expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
assert_equal expected, result
end
test 'nested jbuilder object via set!' do
to_nest = Jbuilder.new{ |json| json.nested_value 'Nested Test' }
result = jbuild do |json|
json.value 'Test'
json.set! :nested, to_nest
end
expected = {'value' => 'Test', 'nested' => {'nested_value' => 'Nested Test'}}
assert_equal expected, result
end
test 'top-level array' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.array! comments do |comment|
json.content comment.content
end
end
assert_equal 'hello', result.first['content']
assert_equal 'world', result.second['content']
end
test 'it allows using next in array block to skip value' do
comments = [ Comment.new('hello', 1), Comment.new('skip', 2), Comment.new('world', 3) ]
result = jbuild do |json|
json.array! comments do |comment|
next if comment.id == 2
json.content comment.content
end
end
assert_equal 2, result.length
assert_equal 'hello', result.first['content']
assert_equal 'world', result.second['content']
end
test 'extract attributes directly from array' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.array! comments, :content, :id
end
assert_equal 'hello', result.first['content']
assert_equal 1, result.first['id']
assert_equal 'world', result.second['content']
assert_equal 2, result.second['id']
end
test 'empty top-level array' do
comments = []
result = jbuild do |json|
json.array! comments do |comment|
json.content comment.content
end
end
assert_equal [], result
end
test 'dynamically set a key/value' do
result = jbuild do |json|
json.set! :each, 'stuff'
end
assert_equal 'stuff', result['each']
end
test 'dynamically set a key/nested child with block' do
result = jbuild do |json|
json.set! :author do
json.name 'David'
json.age 32
end
end
assert_equal 'David', result['author']['name']
assert_equal 32, result['author']['age']
end
test 'dynamically sets a collection' do
comments = [ Comment.new('hello', 1), Comment.new('world', 2) ]
result = jbuild do |json|
json.set! :comments, comments, :content
end
assert_equal ['content'], result['comments'].first.keys
assert_equal 'hello', result['comments'].first['content']
assert_equal 'world', result['comments'].second['content']
end
test 'query like object' do
result = jbuild do |json|
json.relations RelationMock.new, :name, :age
end
assert_equal 2, result['relations'].length
assert_equal 'Bob', result['relations'][0]['name']
assert_equal 50, result['relations'][1]['age']
end
test 'initialize via options hash' do
jbuilder = Jbuilder.new(key_formatter: 1, ignore_nil: 2)
assert_equal 1, jbuilder.instance_eval{ @key_formatter }
assert_equal 2, jbuilder.instance_eval{ @ignore_nil }
end
test 'key_format! with parameter' do
result = jbuild do |json|
json.key_format! camelize: [:lower]
json.camel_style 'for JS'
end
assert_equal ['camelStyle'], result.keys
end
test 'key_format! with parameter not as an array' do
result = jbuild do |json|
json.key_format! :camelize => :lower
json.camel_style 'for JS'
end
assert_equal ['camelStyle'], result.keys
end
test 'key_format! propagates to child elements' do
result = jbuild do |json|
json.key_format! :upcase
json.level1 'one'
json.level2 do
json.value 'two'
end
end
assert_equal 'one', result['LEVEL1']
assert_equal 'two', result['LEVEL2']['VALUE']
end
test 'key_format! resets after child element' do
result = jbuild do |json|
json.level2 do
json.key_format! :upcase
json.value 'two'
end
json.level1 'one'
end
assert_equal 'two', result['level2']['VALUE']
assert_equal 'one', result['level1']
end
test 'key_format! with no parameter' do
result = jbuild do |json|
json.key_format! :upcase
json.lower 'Value'
end
assert_equal ['LOWER'], result.keys
end
test 'key_format! with multiple steps' do
result = jbuild do |json|
json.key_format! :upcase, :pluralize
json.pill 'foo'
end
assert_equal ['PILLs'], result.keys
end
test 'key_format! with lambda/proc' do
result = jbuild do |json|
json.key_format! ->(key){ key + ' and friends' }
json.oats 'foo'
end
assert_equal ['oats and friends'], result.keys
end
test 'default key_format!' do
Jbuilder.key_format camelize: :lower
result = jbuild{ |json| json.camel_style 'for JS' }
assert_equal ['camelStyle'], result.keys
end
test 'do not use default key formatter directly' do
Jbuilder.key_format
jbuild{ |json| json.key 'value' }
formatter = Jbuilder.send(:class_variable_get, '@@key_formatter')
cache = formatter.instance_variable_get('@cache')
assert_empty cache
end
test 'ignore_nil! without a parameter' do
result = jbuild do |json|
json.ignore_nil!
json.test nil
end
assert_empty result.keys
end
test 'ignore_nil! with parameter' do
result = jbuild do |json|
json.ignore_nil! true
json.name 'Bob'
json.dne nil
end
assert_equal ['name'], result.keys
result = jbuild do |json|
json.ignore_nil! false
json.name 'Bob'
json.dne nil
end
assert_equal ['name', 'dne'], result.keys
end
test 'default ignore_nil!' do
Jbuilder.ignore_nil
result = jbuild do |json|
json.name 'Bob'
json.dne nil
end
assert_equal ['name'], result.keys
Jbuilder.send(:class_variable_set, '@@ignore_nil', false)
end
test 'nil!' do
result = jbuild do |json|
json.key 'value'
json.nil!
end
assert_nil result
end
test 'null!' do
result = jbuild do |json|
json.key 'value'
json.null!
end
assert_nil result
end
test 'null! in a block' do
result = jbuild do |json|
json.author do
json.name 'David'
end
json.author do
json.null!
end
end
assert result.key?('author')
assert_nil result['author']
end
test 'empty attributes respond to empty?' do
attributes = Jbuilder.new.attributes!
assert attributes.empty?
assert attributes.blank?
assert !attributes.present?
end
test 'throws ArrayError when trying to add a key to an array' do
assert_raise Jbuilder::ArrayError do
jbuild do |json|
json.array! %w[foo bar]
json.fizz "buzz"
end
end
end
test 'throws NullError when trying to add properties to null' do
assert_raise Jbuilder::NullError do
jbuild do |json|
json.null!
json.foo 'bar'
end
end
end
test 'throws NullError when trying to add properties to null using block syntax' do
assert_raise Jbuilder::NullError do
jbuild do |json|
json.author do
json.null!
end
json.author do
json.name "Pavel"
end
end
end
end
test "throws MergeError when trying to merge array with non-empty hash" do
assert_raise Jbuilder::MergeError do
jbuild do |json|
json.name "Daniel"
json.merge! []
end
end
end
test "throws MergeError when trying to merge hash with array" do
assert_raise Jbuilder::MergeError do
jbuild do |json|
json.array!
json.merge!({})
end
end
end
test "throws MergeError when trying to merge invalid objects" do
assert_raise Jbuilder::MergeError do
jbuild do |json|
json.name "Daniel"
json.merge! "Nope"
end
end
end
end
jbuilder-2.7.0/README.md 0000644 0000041 0000041 00000015105 13273321662 014636 0 ustar www-data www-data # Jbuilder
Jbuilder gives you a simple DSL for declaring JSON structures that beats
manipulating giant hash structures. This is particularly helpful when the
generation process is fraught with conditionals and loops. Here's a simple
example:
``` ruby
# app/views/messages/show.json.jbuilder
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)
json.author do
json.name @message.creator.name.familiar
json.email_address @message.creator.email_address_with_name
json.url url_for(@message.creator, format: :json)
end
if current_user.admin?
json.visitors calculate_visitors(@message)
end
json.comments @message.comments, :content, :created_at
json.attachments @message.attachments do |attachment|
json.filename attachment.filename
json.url url_for(attachment)
end
```
This will build the following structure:
``` javascript
{
"content": "
This is serious monkey business
",
"created_at": "2011-10-29T20:45:28-05:00",
"updated_at": "2011-10-29T20:45:28-05:00",
"author": {
"name": "David H.",
"email_address": "'David Heinemeier Hansson' ",
"url": "http://example.com/users/1-david.json"
},
"visitors": 15,
"comments": [
{ "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
{ "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
],
"attachments": [
{ "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
{ "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
]
}
```
To define attribute and structure names dynamically, use the `set!` method:
``` ruby
json.set! :author do
json.set! :name, 'David'
end
# => {"author": { "name": "David" }}
```
Top level arrays can be handled directly. Useful for index and other collection actions.
``` ruby
# @comments = @post.comments
json.array! @comments do |comment|
next if comment.marked_as_spam_by?(current_user)
json.body comment.body
json.author do
json.first_name comment.author.first_name
json.last_name comment.author.last_name
end
end
# => [ { "body": "great post...", "author": { "first_name": "Joe", "last_name": "Bloe" }} ]
```
You can also extract attributes from array directly.
``` ruby
# @people = People.all
json.array! @people, :id, :name
# => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]
```
Jbuilder objects can be directly nested inside each other. Useful for composing objects.
``` ruby
class Person
# ... Class Definition ... #
def to_builder
Jbuilder.new do |person|
person.(self, :name, :age)
end
end
end
class Company
# ... Class Definition ... #
def to_builder
Jbuilder.new do |company|
company.name name
company.president president.to_builder
end
end
end
company = Company.new('Doodle Corp', Person.new('John Stobs', 58))
company.to_builder.target!
# => {"name":"Doodle Corp","president":{"name":"John Stobs","age":58}}
```
You can either use Jbuilder stand-alone or directly as an ActionView template
language. When required in Rails, you can create views a la show.json.jbuilder
(the json is already yielded):
``` ruby
# Any helpers available to views are available to the builder
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)
json.author do
json.name @message.creator.name.familiar
json.email_address @message.creator.email_address_with_name
json.url url_for(@message.creator, format: :json)
end
if current_user.admin?
json.visitors calculate_visitors(@message)
end
```
You can use partials as well. The following will render the file
`views/comments/_comments.json.jbuilder`, and set a local variable
`comments` with all this message's comments, which you can use inside
the partial.
```ruby
json.partial! 'comments/comments', comments: @message.comments
```
It's also possible to render collections of partials:
```ruby
json.array! @posts, partial: 'posts/post', as: :post
# or
json.partial! 'posts/post', collection: @posts, as: :post
# or
json.partial! partial: 'posts/post', collection: @posts, as: :post
# or
json.comments @post.comments, partial: 'comments/comment', as: :comment
```
You can pass any objects into partial templates with or without `:locals` option.
```ruby
json.partial! 'sub_template', locals: { user: user }
# or
json.partial! 'sub_template', user: user
```
You can explicitly make Jbuilder object return null if you want:
``` ruby
json.extract! @post, :id, :title, :content, :published_at
json.author do
if @post.anonymous?
json.null! # or json.nil!
else
json.first_name @post.author_first_name
json.last_name @post.author_last_name
end
end
```
To prevent Jbuilder from including null values in the output, you can use the `ignore_nil!` method:
```ruby
json.ignore_nil!
json.foo nil
json.bar "bar"
# => { "bar": "bar" }
```
Fragment caching is supported, it uses `Rails.cache` and works like caching in
HTML templates:
```ruby
json.cache! ['v1', @person], expires_in: 10.minutes do
json.extract! @person, :name, :age
end
```
You can also conditionally cache a block by using `cache_if!` like this:
```ruby
json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
json.extract! @person, :name, :age
end
```
If you are rendering fragments for a collection of objects, have a look at
`jbuilder_cache_multi` gem. It uses fetch_multi (>= Rails 4.1) to fetch
multiple keys at once.
Keys can be auto formatted using `key_format!`, this can be used to convert
keynames from the standard ruby_format to camelCase:
``` ruby
json.key_format! camelize: :lower
json.first_name 'David'
# => { "firstName": "David" }
```
You can set this globally with the class method `key_format` (from inside your
environment.rb for example):
``` ruby
Jbuilder.key_format camelize: :lower
```
Faster JSON backends
--------------------
Jbuilder uses MultiJson, which by default will use the JSON gem. That gem is
currently tangled with ActiveSupport's all-Ruby `#to_json` implementation,
which is slow (fixed in Rails >= 4.1). For faster Jbuilder rendering, you can
specify something like the Yajl JSON generator instead. You'll need to include
the `yajl-ruby` gem in your Gemfile and then set the following configuration
for MultiJson:
``` ruby
require 'multi_json'
MultiJson.use :yajl
```
## Contributing to Jbuilder
Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose
features and discuss issues.
See [CONTRIBUTING](CONTRIBUTING.md).
## License
Jbuilder is released under the [MIT License](http://www.opensource.org/licenses/MIT).
jbuilder-2.7.0/gemfiles/ 0000755 0000041 0000041 00000000000 13273321662 015150 5 ustar www-data www-data jbuilder-2.7.0/gemfiles/rails_4_2.gemfile 0000644 0000041 0000041 00000000363 13273321662 020262 0 ustar www-data www-data # This file was generated by Appraisal
source "https://rubygems.org"
gem "rake"
gem "mocha", require: false
gem "appraisal"
gem "pry"
gem "railties", "~> 4.2.0"
gem "actionpack", "~> 4.2.0"
gem "activemodel", "~> 4.2.0"
gemspec path: "../"
jbuilder-2.7.0/gemfiles/rails_5_0.gemfile 0000644 0000041 0000041 00000000363 13273321662 020261 0 ustar www-data www-data # This file was generated by Appraisal
source "https://rubygems.org"
gem "rake"
gem "mocha", require: false
gem "appraisal"
gem "pry"
gem "railties", "~> 5.0.0"
gem "actionpack", "~> 5.0.0"
gem "activemodel", "~> 5.0.0"
gemspec path: "../"
jbuilder-2.7.0/gemfiles/rails_5_1.gemfile 0000644 0000041 0000041 00000000416 13273321662 020261 0 ustar www-data www-data # This file was generated by Appraisal
source "https://rubygems.org"
gem "rake"
gem "mocha", require: false
gem "appraisal"
gem "pry"
gem "railties", ">= 5.1.0", "< 5.2"
gem "actionpack", ">= 5.1.0", "< 5.2"
gem "activemodel", ">= 5.1.0", "< 5.2"
gemspec path: "../"
jbuilder-2.7.0/CHANGELOG.md 0000644 0000041 0000041 00000023772 13273321662 015201 0 ustar www-data www-data # Changelog
2.6.4
-----
* Drop the pessimistic upper-bound restriction on Active Support and MultiJSON to prevent future gemfile resolution deadlocks *DHH*
2.6.3
-----
* Support Rails 5.1
2.6.2
-----
* Fix thor warnings
2.6.1
-----
* [Optimize root caches with cache_root!](https://github.com/rails/jbuilder/pull/370)
2.6.0
-----
* [Rails 5 cache! with expire support](https://github.com/rails/jbuilder/commit/d61e3354563863731bc1f358f495b1dbb7ae9d32)
* [Generated view DRYed by using model partial](https://github.com/rails/jbuilder/commit/83256f4d7e9211c9dc47972feaed7fd31e4f7cac)
2.5.0
-----
* [Rails 5 compatibility](https://github.com/rails/jbuilder/commit/64c510ec69d9e63b73ffd5942e802d21a7d14701)
2.4.1
-----
* [Fix controller generators to be Rails 5 compatible](https://github.com/rails/jbuilder/commit/2dc6203c5c4a98701d5b64c2a5200835a48bb533)
2.4.0
-----
* [Rails 5 compatibility](https://github.com/rails/jbuilder/commit/4aa2cfcc19a4634d65a28ffc75f0ac0cb8304115)
2.3.2
-----
* [Remove Mime Types deprecation message](https://github.com/rails/jbuilder/commit/5ba4e4ac654cc8388619538f576fe234659b84ec)
2.3.1
-----
* [Explicitly require ostruct to prevent NameError](https://github.com/rails/jbuilder/pull/281)
2.3.0
-----
* [Add new in-place partial invocation support](https://github.com/rails/jbuilder/commit/1feda7ee605c136e59fb4de970f4674de518e6de)
* [Add implicit partial rendering for AM::Models](https://github.com/rails/jbuilder/commit/4d5bf7d0ea92765adb7be36834e84f9855a061df)
* [Generate API controller if Rails API option is enabled](https://github.com/rails/jbuilder/commit/db68f6bd327cf42b47ef22d455fb5721a8c2cf5f)
* [JBuilder's templates have less priority than app templates](https://github.com/rails/jbuilder/commit/7c1a5f25603ec1f4e51fba3dbba9db23726a5d69)
* [Add AC::Helpers module to jbuilder for api only apps](https://github.com/rails/jbuilder/commit/7cf1d1eb7d125caf38309b5427952030011c1aa0)
2.2.16
------
* [Fix NoMethodError around `api_only` in railtie](https://github.com/rails/jbuilder/commit/b08d1da10b14720b46d383b2917e336060fd9ffa)
2.2.14
------
* [Make Jbuilder compatible with Rails API](https://github.com/rails/jbuilder/commit/29c0014a9c954c990075d42c45c66075260e924b)
2.2.13
------
* Several performance optimizations: [#260](https://github.com/rails/jbuilder/pull/260) & [#261](https://github.com/rails/jbuilder/pull/261)
2.2.12
------
* [Replace explicit block calls with yield for performance](https://github.com/rails/jbuilder/commit/3184f941276ad03a071cf977133d1a32302afa47)
2.2.11
------
* Generate the templates for Rails 5+ [#258](https://github.com/rails/jbuilder/pull/258) [@amatsuda](https://github.com/amatsuda)
2.2.10
------
* Add Jbuilder::Blank#empty? to tell if attributes are empty [#257](https://github.com/rails/jbuilder/pull/257) [@a2ikm](https://github.com/a2ikm)
2.2.9
-----
* Support `partial!` call with `locals` option in `JbuilderTemplate` [#251](https://github.com/rails/jbuilder/pull/251)
2.2.8
-----
* [Raise ArrayError when trying to add key to an array](https://github.com/rails/jbuilder/commit/869e4be1ad165ce986d8fca78311bdd3ed166087)
2.2.7
-----
* [Make Blank object serializable with Marshal](https://github.com/rails/jbuilder/commit/7083f28d8b665aa60d0d1b1927ae88bb5c6290ba)
2.2.6
-----
* [Make sure dependency tracker loads after template handler](https://github.com/rails/jbuilder/commit/3ba404b1207b557e14771c90b8832bc01ae67a42)
2.2.5
-----
* [Refactor merge block behavior to raise error for unexpected values](https://github.com/rails/jbuilder/commit/4503162fb26f53f613fc83ac081fd244748b6fe9)
2.2.4
-----
* [Typecast locals hash key during collection render](https://github.com/rails/jbuilder/commit/a6b0c8651a08e01cb53eee38e211c65423f275f7)
2.2.3
-----
* [Move template handler registration into railtie](https://github.com/rails/jbuilder/commit/c8acc5cea6da2a79b7b345adc301cb5ff2517647)
* [Do not capture the block where it is possible](https://github.com/rails/jbuilder/commit/973b382c3924cb59fc0e4e25266b18e74d41d646)
2.2.2
-----
* [Fix `Jbuilder#merge!` inside block](https://github.com/rails/jbuilder/commit/a7b328552eb0d36315f75bff813bea7eecf8c1d7)
2.2.1
-----
* [Fix empty block handling](https://github.com/rails/jbuilder/commit/972a11141403269e9b17b45b0c95f8a9788245ee)
2.2.0
-----
* [Allow to skip `array!` iterations by calling `next`](https://github.com/rails/jbuilder/commit/81a63308fb9d5002519dd871f829ccc58067251a)
2.1.2
-----
* [Cast array-like objects to array before merging](https://github.com/rails/jbuilder/commit/7b8c8a1cb09b7f3dd26e5643ebbd6b2ec67185db)
2.1.1
-----
* [Remove unused file](https://github.com/rails/jbuilder/commit/e49e1047976fac93b8242ab212c7b1a463b70809)
2.1.0
-----
* [Blocks and their extract! shortcuts are additive by default](https://github.com/rails/jbuilder/commit/a49390736c5f6e2d7a31111df6531bc28dba9fb1)
2.0.8
-----
* [Eliminate circular dependencies](https://github.com/rails/jbuilder/commit/0879484dc74e7be93b695f66e3708ba48cdb1be3)
* [Support cache key generation for complex objects](https://github.com/rails/jbuilder/commit/ca9622cca30c1112dd4408fcb2e658849abe1dd5)
* [Remove JbuilderProxy class](https://github.com/rails/jbuilder/commit/5877482fc7da3224e42d4f72a1386f7a3a08173b)
* [Move KeyFormatter into a separate file](https://github.com/rails/jbuilder/commit/13fee8464ff53ce853030114283c03c135c052b6)
* [Move NullError into a separate file](https://github.com/rails/jbuilder/commit/13fee8464ff53ce853030114283c03c135c052b6)
2.0.7
-----
* [Add destroy notice to scaffold generator](https://github.com/rails/jbuilder/commit/8448e86f8cdfa0f517bd59576947875775a1d43c)
2.0.6
-----
* [Use render short form in controller generator](https://github.com/rails/jbuilder/commit/acf37320a7cea7fcc70c791bc94bd5f46b8349ff)
2.0.5
-----
* [Fix edgecase when json is defined as a method](https://github.com/rails/jbuilder/commit/ca711a0c0a5760e26258ce2d93c14bef8fff0ead)
2.0.4
-----
* [Add cache_if! to conditionally cache JSON fragments](https://github.com/rails/jbuilder/commit/14a5afd8a2c939a6fd710d355a194c114db96eb2)
2.0.3
-----
* [Pass options when calling cache_fragment_name](https://github.com/rails/jbuilder/commit/07c2cc7486fe9ef423d7bc821b83f6d485f330e0)
2.0.2
-----
* [Fix Dependency Tracking fail to detect single-quoted partial correctly](https://github.com/rails/jbuilder/commit/448679a6d3098eb34d137f782a05f1767711991a)
* [Prevent Dependency Tracker constants leaking into global namespace](https://github.com/rails/jbuilder/commit/3544b288b63f504f46fa8aafd1d17ee198d77536)
2.0.1
-----
* [Dependency tracking support for Rails 3 with cache_digest gem](https://github.com/rails/jbuilder/commit/6b471d7a38118e8f7645abec21955ef793401daf)
2.0.0
-----
* [Respond to PUT/PATCH API request with :ok](https://github.com/rails/jbuilder/commit/9dbce9c12181e89f8f472ac23c764ffe8438040a)
* [Remove Ruby 1.8 support](https://github.com/rails/jbuilder/commit/d53fff42d91f33d662eafc2561c4236687ecf6c9)
* [Remove deprecated two argument block call](https://github.com/rails/jbuilder/commit/07a35ee7e79ae4b06dba9dbff5c4e07c1e627218)
* [Make Jbuilder object initialize with single hash](https://github.com/rails/jbuilder/commit/38bf551db0189327aaa90b9be010c0d1b792c007)
* [Track template dependencies](https://github.com/rails/jbuilder/commit/8e73cea39f60da1384afd687cc8e5e399630d8cc)
* [Expose merge! method](https://github.com/rails/jbuilder/commit/0e2eb47f6f3c01add06a1a59b37cdda8baf24f29)
1.5.3
-----
* [Generators add `:id` column by default](https://github.com/rails/jbuilder/commit/0b52b86773e48ac2ce35d4155c7b70ad8b3e8937)
1.5.2
-----
* [Nil-collection should be treated as empty array](https://github.com/rails/jbuilder/commit/2f700bb00ab663c6b7fcb28d2967aeb989bd43c7)
1.5.1
-----
* [Expose template lookup options](https://github.com/rails/jbuilder/commit/404c18dee1af96ac6d8052a04062629ef1db2945)
1.5.0
-----
* [Do not perform any caching when `controller.perform_caching` is false](https://github.com/rails/jbuilder/commit/94633facde1ac43580f8cd5e13ae9cc83e1da8f4)
* [Add partial collection rendering](https://github.com/rails/jbuilder/commit/e8c10fc885e41b18178aaf4dcbc176961c928d76)
* [Deprecate extract! calling private methods](https://github.com/rails/jbuilder/commit/b9e19536c2105d7f2e813006bbcb8ca5730d28a3)
* [Add array of partials rendering](https://github.com/rails/jbuilder/commit/7d7311071720548047f98f14ad013c560b8d9c3a)
1.4.2
-----
* [Require MIME dependency explicitly](https://github.com/rails/jbuilder/commit/b1ed5ac4f08b056f8839b4b19b43562e81e02a59)
1.4.1
-----
* [Removed deprecated positioned arguments initializer support](https://github.com/rails/jbuilder/commit/6e03e0452073eeda77e6dfe66aa31e5ec67a3531)
* [Deprecate two-arguments block calling](https://github.com/rails/jbuilder/commit/2b10bb058bb12bc782cbcc16f6ec67b489e5ed43)
1.4.0
-----
* [Add quick collection attribute extraction](https://github.com/rails/jbuilder/commit/c2b966cf653ea4264fbb008b8cc6ce5359ebe40a)
* [Block has priority over attributes extraction](https://github.com/rails/jbuilder/commit/77c24766362c02769d81dac000b1879a9e4d4a00)
* [Meaningful error messages when adding properties to null](https://github.com/rails/jbuilder/commit/e26764602e34b3772e57e730763d512e59489e3b)
* [Do not enforce template format, enforce handlers instead](https://github.com/rails/jbuilder/commit/72576755224b15da45e50cbea877679800ab1398)
1.3.0
-----
* [Add nil! method for nil JSON](https://github.com/rails/jbuilder/commit/822a906f68664f61a1209336bb681077692c8475)
1.2.1
-----
* [Added explicit dependency for MultiJson](https://github.com/rails/jbuilder/commit/4d58eacb6cd613679fb243484ff73a79bbbff2d2)
1.2.0
-----
* Multiple documentation improvements and internal refactoring
* [Fixes fragment caching to work with latest digests](https://github.com/rails/jbuilder/commit/da937d6b8732124074c612abb7ff38868d1d96c0)
1.0.2
-----
* [Support non-Enumerable collections](https://github.com/rails/jbuilder/commit/4c20c59bf8131a1e419bb4ebf84f2b6bdcb6b0cf)
* [Ensure that the default URL is in json format](https://github.com/rails/jbuilder/commit/0b46782fb7b8c34a3c96afa801fe27a5a97118a4)
1.0.0
-----
* Adopt Semantic Versioning
* Add rails generators
jbuilder-2.7.0/Appraisals 0000644 0000041 0000041 00000000621 13273321662 015376 0 ustar www-data www-data appraise "rails-4-2" do
gem "railties", "~> 4.2.0"
gem "actionpack", "~> 4.2.0"
gem "activemodel", "~> 4.2.0"
end
appraise "rails-5-0" do
gem "railties", "~> 5.0.0"
gem "actionpack", "~> 5.0.0"
gem "activemodel", "~> 5.0.0"
end
appraise "rails-5-1" do
gem "railties", ">= 5.1.0", "< 5.2"
gem "actionpack", ">= 5.1.0", "< 5.2"
gem "activemodel", ">= 5.1.0", "< 5.2"
end
jbuilder-2.7.0/.gitignore 0000644 0000041 0000041 00000000063 13273321662 015344 0 ustar www-data www-data tmp
gemfiles/*.lock
Gemfile.lock
.ruby-version
pkg
jbuilder-2.7.0/Rakefile 0000644 0000041 0000041 00000000570 13273321662 015024 0 ustar www-data www-data require "bundler/setup"
require "bundler/gem_tasks"
require "rake/testtask"
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
require "appraisal/task"
Appraisal::Task.new
task default: :appraisal
else
Rake::TestTask.new do |test|
require "rails/version"
test.libs << "test"
test.test_files = FileList["test/*_test.rb"]
end
task default: :test
end
jbuilder-2.7.0/lib/ 0000755 0000041 0000041 00000000000 13273321662 014123 5 ustar www-data www-data jbuilder-2.7.0/lib/generators/ 0000755 0000041 0000041 00000000000 13273321662 016274 5 ustar www-data www-data jbuilder-2.7.0/lib/generators/rails/ 0000755 0000041 0000041 00000000000 13273321662 017406 5 ustar www-data www-data jbuilder-2.7.0/lib/generators/rails/jbuilder_generator.rb 0000644 0000041 0000041 00000003017 13273321662 023602 0 ustar www-data www-data require 'rails/generators/named_base'
require 'rails/generators/resource_helpers'
module Rails
module Generators
class JbuilderGenerator < NamedBase # :nodoc:
include Rails::Generators::ResourceHelpers
source_root File.expand_path('../templates', __FILE__)
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
def create_root_folder
path = File.join('app/views', controller_file_path)
empty_directory path unless File.directory?(path)
end
def copy_view_files
%w(index show).each do |view|
filename = filename_with_extensions(view)
template filename, File.join('app/views', controller_file_path, filename)
end
template filename_with_extensions('partial'), File.join('app/views', controller_file_path, filename_with_extensions("_#{singular_table_name}"))
end
protected
def attributes_names
[:id] + super
end
def filename_with_extensions(name)
[name, :json, :jbuilder] * '.'
end
def attributes_list_with_timestamps
attributes_list(attributes_names + %w(created_at updated_at))
end
def attributes_list(attributes = attributes_names)
if self.attributes.any? {|attr| attr.name == 'password' && attr.type == :digest}
attributes = attributes.reject {|name| %w(password password_confirmation).include? name}
end
attributes.map { |a| ":#{a}"} * ', '
end
end
end
end
jbuilder-2.7.0/lib/generators/rails/scaffold_controller_generator.rb 0000644 0000041 0000041 00000000502 13273321662 026022 0 ustar www-data www-data require 'rails/generators'
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
module Rails
module Generators
class ScaffoldControllerGenerator
source_paths << File.expand_path('../templates', __FILE__)
hook_for :jbuilder, type: :boolean, default: true
end
end
end
jbuilder-2.7.0/lib/generators/rails/templates/ 0000755 0000041 0000041 00000000000 13273321662 021404 5 ustar www-data www-data jbuilder-2.7.0/lib/generators/rails/templates/index.json.jbuilder 0000644 0000041 0000041 00000000207 13273321662 025204 0 ustar www-data www-data json.array! @<%= plural_table_name %>, partial: '<%= plural_table_name %>/<%= singular_table_name %>', as: :<%= singular_table_name %>
jbuilder-2.7.0/lib/generators/rails/templates/api_controller.rb 0000644 0000041 0000041 00000003702 13273321662 024747 0 ustar www-data www-data <% if namespaced? -%>
require_dependency "<%= namespaced_file_path %>/application_controller"
<% end -%>
<% module_namespacing do -%>
class <%= controller_class_name %>Controller < ApplicationController
before_action :set_<%= singular_table_name %>, only: [:show, :update, :destroy]
# GET <%= route_url %>
# GET <%= route_url %>.json
def index
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
end
# GET <%= route_url %>/1
# GET <%= route_url %>/1.json
def show
end
# POST <%= route_url %>
# POST <%= route_url %>.json
def create
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
if @<%= orm_instance.save %>
render :show, status: :created, location: <%= "@#{singular_table_name}" %>
else
render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
end
end
# PATCH/PUT <%= route_url %>/1
# PATCH/PUT <%= route_url %>/1.json
def update
if @<%= orm_instance.update("#{singular_table_name}_params") %>
render :show, status: :ok, location: <%= "@#{singular_table_name}" %>
else
render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
end
end
# DELETE <%= route_url %>/1
# DELETE <%= route_url %>/1.json
def destroy
@<%= orm_instance.destroy %>
end
private
# Use callbacks to share common setup or constraints between actions.
def set_<%= singular_table_name %>
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
end
# Never trust parameters from the scary internet, only allow the white list through.
def <%= "#{singular_table_name}_params" %>
<%- if attributes_names.empty? -%>
params.fetch(<%= ":#{singular_table_name}" %>, {})
<%- else -%>
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
<%- end -%>
end
end
<% end -%>
jbuilder-2.7.0/lib/generators/rails/templates/partial.json.jbuilder 0000644 0000041 0000041 00000000244 13273321662 025532 0 ustar www-data www-data json.extract! <%= singular_table_name %>, <%= attributes_list_with_timestamps %>
json.url <%= singular_table_name %>_url(<%= singular_table_name %>, format: :json)
jbuilder-2.7.0/lib/generators/rails/templates/controller.rb 0000644 0000041 0000041 00000005413 13273321662 024117 0 ustar www-data www-data <% if namespaced? -%>
require_dependency "<%= namespaced_file_path %>/application_controller"
<% end -%>
<% module_namespacing do -%>
class <%= controller_class_name %>Controller < ApplicationController
before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
# GET <%= route_url %>
# GET <%= route_url %>.json
def index
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
end
# GET <%= route_url %>/1
# GET <%= route_url %>/1.json
def show
end
# GET <%= route_url %>/new
def new
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
end
# GET <%= route_url %>/1/edit
def edit
end
# POST <%= route_url %>
# POST <%= route_url %>.json
def create
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
respond_to do |format|
if @<%= orm_instance.save %>
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
format.json { render :show, status: :created, location: <%= "@#{singular_table_name}" %> }
else
format.html { render :new }
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
end
end
end
# PATCH/PUT <%= route_url %>/1
# PATCH/PUT <%= route_url %>/1.json
def update
respond_to do |format|
if @<%= orm_instance.update("#{singular_table_name}_params") %>
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
format.json { render :show, status: :ok, location: <%= "@#{singular_table_name}" %> }
else
format.html { render :edit }
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
end
end
end
# DELETE <%= route_url %>/1
# DELETE <%= route_url %>/1.json
def destroy
@<%= orm_instance.destroy %>
respond_to do |format|
format.html { redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %> }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_<%= singular_table_name %>
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
end
# Never trust parameters from the scary internet, only allow the white list through.
def <%= "#{singular_table_name}_params" %>
<%- if attributes_names.empty? -%>
params.fetch(<%= ":#{singular_table_name}" %>, {})
<%- else -%>
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
<%- end -%>
end
end
<% end -%>
jbuilder-2.7.0/lib/generators/rails/templates/show.json.jbuilder 0000644 0000041 0000041 00000000175 13273321662 025061 0 ustar www-data www-data json.partial! "<%= plural_table_name %>/<%= singular_table_name %>", <%= singular_table_name %>: @<%= singular_table_name %>
jbuilder-2.7.0/lib/jbuilder/ 0000755 0000041 0000041 00000000000 13273321662 015723 5 ustar www-data www-data jbuilder-2.7.0/lib/jbuilder/railtie.rb 0000644 0000041 0000041 00000001742 13273321662 017705 0 ustar www-data www-data require 'rails/railtie'
require 'jbuilder/jbuilder_template'
class Jbuilder
class Railtie < ::Rails::Railtie
initializer :jbuilder do
ActiveSupport.on_load :action_view do
ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
require 'jbuilder/dependency_tracker'
end
if Rails::VERSION::MAJOR >= 5
module ::ActionController
module ApiRendering
include ActionView::Rendering
end
end
ActiveSupport.on_load :action_controller do
if self == ActionController::API
include ActionController::Helpers
include ActionController::ImplicitRender
end
end
end
end
if Rails::VERSION::MAJOR >= 4
generators do |app|
Rails::Generators.configure! app.config.generators
Rails::Generators.hidden_namespaces.uniq!
require 'generators/rails/scaffold_controller_generator'
end
end
end
end
jbuilder-2.7.0/lib/jbuilder/errors.rb 0000644 0000041 0000041 00000001102 13273321662 017556 0 ustar www-data www-data require 'jbuilder/jbuilder'
class Jbuilder
class NullError < ::NoMethodError
def self.build(key)
message = "Failed to add #{key.to_s.inspect} property to null object"
new(message)
end
end
class ArrayError < ::StandardError
def self.build(key)
message = "Failed to add #{key.to_s.inspect} property to an array"
new(message)
end
end
class MergeError < ::StandardError
def self.build(current_value, updates)
message = "Can't merge #{updates.inspect} into #{current_value.inspect}"
new(message)
end
end
end
jbuilder-2.7.0/lib/jbuilder/jbuilder_template.rb 0000644 0000041 0000041 00000015132 13273321662 021745 0 ustar www-data www-data require 'jbuilder/jbuilder'
require 'action_dispatch/http/mime_type'
require 'active_support/cache'
class JbuilderTemplate < Jbuilder
class << self
attr_accessor :template_lookup_options
end
self.template_lookup_options = { handlers: [:jbuilder] }
def initialize(context, *args)
@context = context
@cached_root = nil
super(*args)
end
def partial!(*args)
if args.one? && _is_active_model?(args.first)
_render_active_model_partial args.first
else
_render_explicit_partial(*args)
end
end
# Caches the json constructed within the block passed. Has the same signature as the `cache` helper
# method in `ActionView::Helpers::CacheHelper` and so can be used in the same way.
#
# Example:
#
# json.cache! ['v1', @person], expires_in: 10.minutes do
# json.extract! @person, :name, :age
# end
def cache!(key=nil, options={})
if @context.controller.perform_caching
value = _cache_fragment_for(key, options) do
_scope { yield self }
end
merge! value
else
yield
end
end
# Caches the json structure at the root using a string rather than the hash structure. This is considerably
# faster, but the drawback is that it only works, as the name hints, at the root. So you cannot
# use this approach to cache deeper inside the hierarchy, like in partials or such. Continue to use #cache! there.
#
# Example:
#
# json.cache_root! @person do
# json.extract! @person, :name, :age
# end
#
# # json.extra 'This will not work either, the root must be exclusive'
def cache_root!(key=nil, options={})
if @context.controller.perform_caching
raise "cache_root! can't be used after JSON structures have been defined" if @attributes.present?
@cached_root = _cache_fragment_for([ :root, key ], options) { yield; target! }
else
yield
end
end
# Conditionally caches the json depending in the condition given as first parameter. Has the same
# signature as the `cache` helper method in `ActionView::Helpers::CacheHelper` and so can be used in
# the same way.
#
# Example:
#
# json.cache_if! !admin?, @person, expires_in: 10.minutes do
# json.extract! @person, :name, :age
# end
def cache_if!(condition, *args)
condition ? cache!(*args, &::Proc.new) : yield
end
def target!
@cached_root || super
end
def array!(collection = [], *args)
options = args.first
if args.one? && _partial_options?(options)
partial! options.merge(collection: collection)
else
super
end
end
def set!(name, object = BLANK, *args)
options = args.first
if args.one? && _partial_options?(options)
_set_inline_partial name, object, options
else
super
end
end
private
def _render_partial_with_options(options)
options.reverse_merge! locals: {}
options.reverse_merge! ::JbuilderTemplate.template_lookup_options
as = options[:as]
if as && options.key?(:collection)
as = as.to_sym
collection = options.delete(:collection)
locals = options.delete(:locals)
array! collection do |member|
member_locals = locals.clone
member_locals.merge! collection: collection
member_locals.merge! as => member
_render_partial options.merge(locals: member_locals)
end
else
_render_partial options
end
end
def _render_partial(options)
options[:locals].merge! json: self
@context.render options
end
def _cache_fragment_for(key, options, &block)
key = _cache_key(key, options)
_read_fragment_cache(key, options) || _write_fragment_cache(key, options, &block)
end
def _read_fragment_cache(key, options = nil)
@context.controller.instrument_fragment_cache :read_fragment, key do
::Rails.cache.read(key, options)
end
end
def _write_fragment_cache(key, options = nil)
@context.controller.instrument_fragment_cache :write_fragment, key do
yield.tap do |value|
::Rails.cache.write(key, value, options)
end
end
end
def _cache_key(key, options)
name_options = options.slice(:skip_digest, :virtual_path)
key = _fragment_name_with_digest(key, name_options)
if @context.respond_to?(:fragment_cache_key)
key = @context.fragment_cache_key(key)
else
key = url_for(key).split('://', 2).last if ::Hash === key
end
::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
end
def _fragment_name_with_digest(key, options)
if @context.respond_to?(:cache_fragment_name)
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
# should be used instead.
@context.cache_fragment_name(key, options)
elsif @context.respond_to?(:fragment_name_with_digest)
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
@context.fragment_name_with_digest(key)
else
key
end
end
def _partial_options?(options)
::Hash === options && options.key?(:as) && options.key?(:partial)
end
def _is_active_model?(object)
object.class.respond_to?(:model_name) && object.respond_to?(:to_partial_path)
end
def _set_inline_partial(name, object, options)
value = if object.nil?
[]
elsif _is_collection?(object)
_scope{ _render_partial_with_options options.merge(collection: object) }
else
locals = ::Hash[options[:as], object]
_scope{ _render_partial_with_options options.merge(locals: locals) }
end
set! name, value
end
def _render_explicit_partial(name_or_options, locals = {})
case name_or_options
when ::Hash
# partial! partial: 'name', foo: 'bar'
options = name_or_options
else
# partial! 'name', locals: {foo: 'bar'}
if locals.one? && (locals.keys.first == :locals)
options = locals.merge(partial: name_or_options)
else
options = { partial: name_or_options, locals: locals }
end
# partial! 'name', foo: 'bar'
as = locals.delete(:as)
options[:as] = as if as.present?
options[:collection] = locals[:collection] if locals.key?(:collection)
end
_render_partial_with_options options
end
def _render_active_model_partial(object)
@context.render object, json: self
end
end
class JbuilderHandler
cattr_accessor :default_format
self.default_format = Mime[:json]
def self.call(template)
# this juggling is required to keep line numbers right in the error
%{__already_defined = defined?(json); json||=JbuilderTemplate.new(self); #{template.source}
json.target! unless (__already_defined && __already_defined != "method")}
end
end
jbuilder-2.7.0/lib/jbuilder/blank.rb 0000644 0000041 0000041 00000000203 13273321662 017332 0 ustar www-data www-data class Jbuilder
class Blank
def ==(other)
super || Blank === other
end
def empty?
true
end
end
end
jbuilder-2.7.0/lib/jbuilder/key_formatter.rb 0000644 0000041 0000041 00000001255 13273321662 021126 0 ustar www-data www-data require 'jbuilder/jbuilder'
require 'active_support/core_ext/array'
class Jbuilder
class KeyFormatter
def initialize(*args)
@format = {}
@cache = {}
options = args.extract_options!
args.each do |name|
@format[name] = []
end
options.each do |name, parameters|
@format[name] = parameters
end
end
def initialize_copy(original)
@cache = {}
end
def format(key)
@cache[key] ||= @format.inject(key.to_s) do |result, args|
func, args = args
if ::Proc === func
func.call result, *args
else
result.send func, *args
end
end
end
end
end
jbuilder-2.7.0/lib/jbuilder/jbuilder.rb 0000644 0000041 0000041 00000000273 13273321662 020052 0 ustar www-data www-data Jbuilder = Class.new(begin
require 'active_support/proxy_object'
ActiveSupport::ProxyObject
rescue LoadError
require 'active_support/basic_object'
ActiveSupport::BasicObject
end)
jbuilder-2.7.0/lib/jbuilder/dependency_tracker.rb 0000644 0000041 0000041 00000003265 13273321662 022107 0 ustar www-data www-data require 'jbuilder/jbuilder'
dependency_tracker = false
begin
require 'action_view'
require 'action_view/dependency_tracker'
dependency_tracker = ::ActionView::DependencyTracker
rescue LoadError
begin
require 'cache_digests'
dependency_tracker = ::CacheDigests::DependencyTracker
rescue LoadError
end
end
if dependency_tracker
class Jbuilder
module DependencyTrackerMethods
# Matches:
# json.partial! "messages/message"
# json.partial!('messages/message')
#
DIRECT_RENDERS = /
\w+\.partial! # json.partial!
\(?\s* # optional parenthesis
(['"])([^'"]+)\1 # quoted value
/x
# Matches:
# json.partial! partial: "comments/comment"
# json.comments @post.comments, partial: "comments/comment", as: :comment
# json.array! @posts, partial: "posts/post", as: :post
# = render partial: "account"
#
INDIRECT_RENDERS = /
(?::partial\s*=>|partial:) # partial: or :partial =>
\s* # optional whitespace
(['"])([^'"]+)\1 # quoted value
/x
def dependencies
direct_dependencies + indirect_dependencies + explicit_dependencies
end
private
def direct_dependencies
source.scan(DIRECT_RENDERS).map(&:second)
end
def indirect_dependencies
source.scan(INDIRECT_RENDERS).map(&:second)
end
end
end
::Jbuilder::DependencyTracker = Class.new(dependency_tracker::ERBTracker)
::Jbuilder::DependencyTracker.send :include, ::Jbuilder::DependencyTrackerMethods
dependency_tracker.register_tracker :jbuilder, ::Jbuilder::DependencyTracker
end
jbuilder-2.7.0/lib/jbuilder.rb 0000644 0000041 0000041 00000020707 13273321662 016256 0 ustar www-data www-data require 'jbuilder/jbuilder'
require 'jbuilder/blank'
require 'jbuilder/key_formatter'
require 'jbuilder/errors'
require 'multi_json'
require 'ostruct'
class Jbuilder
@@key_formatter = nil
@@ignore_nil = false
def initialize(options = {})
@attributes = {}
@key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
@ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
yield self if ::Kernel.block_given?
end
# Yields a builder and automatically turns the result into a JSON string
def self.encode(*args, &block)
new(*args, &block).target!
end
BLANK = Blank.new
NON_ENUMERABLES = [ ::Struct, ::OpenStruct ].to_set
def set!(key, value = BLANK, *args)
result = if ::Kernel.block_given?
if !_blank?(value)
# json.comments @post.comments { |comment| ... }
# { "comments": [ { ... }, { ... } ] }
_scope{ array! value, &::Proc.new }
else
# json.comments { ... }
# { "comments": ... }
_merge_block(key){ yield self }
end
elsif args.empty?
if ::Jbuilder === value
# json.age 32
# json.person another_jbuilder
# { "age": 32, "person": { ... }
value.attributes!
else
# json.age 32
# { "age": 32 }
value
end
elsif _is_collection?(value)
# 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@loudthinking.com" } }
_merge_block(key){ extract! value, *args }
end
_set_value key, result
end
def method_missing(*args)
if ::Kernel.block_given?
set!(*args, &::Proc.new)
else
set!(*args)
end
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" }
#
def key_format!(*args)
@key_formatter = KeyFormatter.new(*args)
end
# Same as the instance method key_format! except sets the default.
def self.key_format(*args)
@@key_formatter = KeyFormatter.new(*args)
end
# If you want to skip adding nil values to your JSON hash. This is useful
# for JSON clients that don't deal well with nil values, and would prefer
# not to receive keys which have null values.
#
# Example:
# json.ignore_nil! false
# json.id User.new.id
#
# { "id": null }
#
# json.ignore_nil!
# json.id User.new.id
#
# {}
#
def ignore_nil!(value = true)
@ignore_nil = value
end
# Same as instance method ignore_nil! except sets the default.
def self.ignore_nil(value = true)
@@ignore_nil = value
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
def child!
@attributes = [] unless ::Array === @attributes
@attributes << _scope{ yield self }
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 } ]
#
# If you are using Ruby 1.9+, you can use the call syntax instead of an explicit extract! call:
#
# json.(@people) { |person| ... }
#
# 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]
def array!(collection = [], *attributes)
array = if collection.nil?
[]
elsif ::Kernel.block_given?
_map_collection(collection, &::Proc.new)
elsif attributes.any?
_map_collection(collection) { |element| extract! element, *attributes }
else
collection.to_a
end
merge! array
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 }
#
# You can also use the call syntax instead of an explicit extract! call:
#
# json.(@person, :name, :age)
def extract!(object, *attributes)
if ::Hash === object
_extract_hash_values(object, attributes)
else
_extract_method_values(object, attributes)
end
end
def call(object, *attributes)
if ::Kernel.block_given?
array! object, &::Proc.new
else
extract! object, *attributes
end
end
# Returns the nil JSON.
def nil!
@attributes = nil
end
alias_method :null!, :nil!
# Returns the attributes of the current builder.
def attributes!
@attributes
end
# Merges hash or array into current builder.
def merge!(hash_or_array)
@attributes = _merge_values(@attributes, hash_or_array)
end
# Encodes the current builder as JSON.
def target!
::MultiJson.dump(@attributes)
end
private
def _extract_hash_values(object, attributes)
attributes.each{ |key| _set_value key, object.fetch(key) }
end
def _extract_method_values(object, attributes)
attributes.each{ |key| _set_value key, object.public_send(key) }
end
def _merge_block(key)
current_value = _blank? ? BLANK : @attributes.fetch(_key(key), BLANK)
raise NullError.build(key) if current_value.nil?
new_value = _scope{ yield self }
_merge_values(current_value, new_value)
end
def _merge_values(current_value, updates)
if _blank?(updates)
current_value
elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates
updates
elsif ::Array === current_value && ::Array === updates
current_value + updates
elsif ::Hash === current_value && ::Hash === updates
current_value.merge(updates)
else
raise MergeError.build(current_value, updates)
end
end
def _key(key)
@key_formatter ? @key_formatter.format(key) : key.to_s
end
def _set_value(key, value)
raise NullError.build(key) if @attributes.nil?
raise ArrayError.build(key) if ::Array === @attributes
return if @ignore_nil && value.nil? or _blank?(value)
@attributes = {} if _blank?
@attributes[_key(key)] = value
end
def _map_collection(collection)
collection.map do |element|
_scope{ yield element }
end - [BLANK]
end
def _scope
parent_attributes, parent_formatter = @attributes, @key_formatter
@attributes = BLANK
yield
@attributes
ensure
@attributes, @key_formatter = parent_attributes, parent_formatter
end
def _is_collection?(object)
_object_respond_to?(object, :map, :count) && NON_ENUMERABLES.none?{ |klass| klass === object }
end
def _blank?(value=@attributes)
BLANK == value
end
def _object_respond_to?(object, *methods)
methods.all?{ |m| object.respond_to?(m) }
end
end
require 'jbuilder/railtie' if defined?(Rails)
jbuilder-2.7.0/CONTRIBUTING.md 0000644 0000041 0000041 00000006146 13273321662 015615 0 ustar www-data www-data Contributing to Jbuilder
=====================
[][travis]
[][gem]
[][codeclimate]
[][gemnasium]
[travis]: https://travis-ci.org/rails/jbuilder
[gem]: https://rubygems.org/gems/jbuilder
[codeclimate]: https://codeclimate.com/github/rails/jbuilder
[gemnasium]: https://gemnasium.com/rails/jbuilder
Jbuilder is work of [many contributors](https://github.com/rails/jbuilder/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rails/jbuilder/pulls), [propose features and discuss issues](https://github.com/rails/jbuilder/issues).
#### Fork the Project
Fork the [project on Github](https://github.com/rails/jbuilder) and check out your copy.
```
git clone https://github.com/contributor/jbuilder.git
cd jbuilder
git remote add upstream https://github.com/rails/jbuilder.git
```
#### Create a Topic Branch
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
```
git checkout master
git pull upstream master
git checkout -b my-feature-branch
```
#### Bundle Install and Test
Ensure that you can build the project and run tests.
```
bundle install
appraisal install
appraisal rake test
```
#### Write Tests
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [test](test).
We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
#### Write Code
Implement your feature or bug fix.
Make sure that `appraisal rake test` completes without errors.
#### Write Documentation
Document any external behavior in the [README](README.md).
#### Commit Changes
Make sure git knows your name and email address:
```
git config --global user.name "Your Name"
git config --global user.email "contributor@example.com"
```
Writing good commit logs is important. A commit log should describe what changed and why.
```
git add ...
git commit
```
#### Push
```
git push origin my-feature-branch
```
#### Make a Pull Request
Visit your forked repo and click the 'New pull request' button. Select your feature branch, fill out the form, and click the 'Create pull request' button. Pull requests are usually reviewed within a few days.
#### Rebase
If you've been working on a change for a while, rebase with upstream/master.
```
git fetch upstream
git rebase upstream/master
git push origin my-feature-branch -f
```
#### Check on Your Pull Request
Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
#### Be Patient
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang in there!
#### Thank You
Please do know that we really appreciate and value your time and work. We love you, really.
jbuilder-2.7.0/jbuilder.gemspec 0000644 0000041 0000041 00000001027 13273321662 016522 0 ustar www-data www-data Gem::Specification.new do |s|
s.name = 'jbuilder'
s.version = '2.7.0'
s.authors = 'David Heinemeier Hansson'
s.email = 'david@basecamp.com'
s.summary = 'Create JSON structures via a Builder-style DSL'
s.homepage = 'https://github.com/rails/jbuilder'
s.license = 'MIT'
s.required_ruby_version = '>= 1.9.3'
s.add_dependency 'activesupport', '>= 4.2.0'
s.add_dependency 'multi_json', '>= 1.2'
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- test/*`.split("\n")
end
jbuilder-2.7.0/Gemfile 0000644 0000041 0000041 00000000151 13273321662 014645 0 ustar www-data www-data source "https://rubygems.org"
gemspec
gem "rake"
gem "mocha", require: false
gem "appraisal"
gem "pry"
jbuilder-2.7.0/MIT-LICENSE 0000644 0000041 0000041 00000002074 13273321662 015014 0 ustar www-data www-data Copyright (c) 2011-2017 David Heinemeier Hansson, 37signals
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.