jwtbuilder 0.0.1 → 2.2.12.jwt
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.travis.yml +28 -0
- data/Appraisals +32 -0
- data/CHANGELOG.md +174 -0
- data/Gemfile +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +260 -0
- data/Rakefile +23 -0
- data/gemfiles/rails_3_0.gemfile +12 -0
- data/gemfiles/rails_3_1.gemfile +12 -0
- data/gemfiles/rails_3_2.gemfile +12 -0
- data/gemfiles/rails_4_0.gemfile +11 -0
- data/gemfiles/rails_4_1.gemfile +11 -0
- data/gemfiles/rails_4_2.gemfile +11 -0
- data/jbuilder.gemspec +18 -0
- data/lib/generators/rails/jbuilder_generator.rb +48 -0
- data/lib/generators/rails/scaffold_controller_generator.rb +12 -0
- data/lib/generators/rails/templates/controller.rb +84 -0
- data/lib/generators/rails/templates/index.json.jbuilder +5 -0
- data/lib/generators/rails/templates/show.json.jbuilder +3 -0
- data/lib/jbuilder/blank.rb +11 -0
- data/lib/jbuilder/dependency_tracker.rb +61 -0
- data/lib/jbuilder/errors.rb +17 -0
- data/lib/jbuilder/jbuilder.rb +7 -0
- data/lib/jbuilder/jbuilder_template.rb +145 -0
- data/lib/jbuilder/key_formatter.rb +34 -0
- data/lib/jbuilder/railtie.rb +21 -0
- data/lib/jbuilder.rb +313 -0
- data/test/jbuilder_dependency_tracker_test.rb +72 -0
- data/test/jbuilder_generator_test.rb +32 -0
- data/test/jbuilder_template_test.rb +343 -0
- data/test/jbuilder_test.rb +686 -0
- data/test/scaffold_controller_generator_test.rb +57 -0
- data/test/test_helper.rb +14 -0
- metadata +48 -8
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
require 'rails/generators/resource_helpers'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Generators
|
6
|
+
class JbuilderGenerator < NamedBase # :nodoc:
|
7
|
+
include Rails::Generators::ResourceHelpers
|
8
|
+
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
10
|
+
|
11
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
12
|
+
|
13
|
+
def create_root_folder
|
14
|
+
path = File.join('app/views', controller_file_path)
|
15
|
+
empty_directory path unless File.directory?(path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_view_files
|
19
|
+
%w(index show).each do |view|
|
20
|
+
filename = filename_with_extensions(view)
|
21
|
+
template filename, File.join('app/views', controller_file_path, filename)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
protected
|
27
|
+
def attributes_names
|
28
|
+
[:id] + super
|
29
|
+
end
|
30
|
+
|
31
|
+
def filename_with_extensions(name)
|
32
|
+
[name, :json, :jbuilder] * '.'
|
33
|
+
end
|
34
|
+
|
35
|
+
def attributes_list_with_timestamps
|
36
|
+
attributes_list(attributes_names + %w(created_at updated_at))
|
37
|
+
end
|
38
|
+
|
39
|
+
def attributes_list(attributes = attributes_names)
|
40
|
+
if self.attributes.any? {|attr| attr.name == 'password' && attr.type == :digest}
|
41
|
+
attributes = attributes.reject {|name| %w(password password_confirmation).include? name}
|
42
|
+
end
|
43
|
+
|
44
|
+
attributes.map { |a| ":#{a}"} * ', '
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Generators
|
6
|
+
class ScaffoldControllerGenerator
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
hook_for :jbuilder, default: true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<% if namespaced? -%>
|
2
|
+
require_dependency "<%= namespaced_file_path %>/application_controller"
|
3
|
+
|
4
|
+
<% end -%>
|
5
|
+
<% module_namespacing do -%>
|
6
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
7
|
+
before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
|
8
|
+
|
9
|
+
# GET <%= route_url %>
|
10
|
+
# GET <%= route_url %>.json
|
11
|
+
def index
|
12
|
+
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
|
13
|
+
end
|
14
|
+
|
15
|
+
# GET <%= route_url %>/1
|
16
|
+
# GET <%= route_url %>/1.json
|
17
|
+
def show
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET <%= route_url %>/new
|
21
|
+
def new
|
22
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
|
23
|
+
end
|
24
|
+
|
25
|
+
# GET <%= route_url %>/1/edit
|
26
|
+
def edit
|
27
|
+
end
|
28
|
+
|
29
|
+
# POST <%= route_url %>
|
30
|
+
# POST <%= route_url %>.json
|
31
|
+
def create
|
32
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
|
33
|
+
|
34
|
+
respond_to do |format|
|
35
|
+
if @<%= orm_instance.save %>
|
36
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
|
37
|
+
format.json { render :show, status: :created, location: <%= "@#{singular_table_name}" %> }
|
38
|
+
else
|
39
|
+
format.html { render :new }
|
40
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# PATCH/PUT <%= route_url %>/1
|
46
|
+
# PATCH/PUT <%= route_url %>/1.json
|
47
|
+
def update
|
48
|
+
respond_to do |format|
|
49
|
+
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
50
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
|
51
|
+
format.json { render :show, status: :ok, location: <%= "@#{singular_table_name}" %> }
|
52
|
+
else
|
53
|
+
format.html { render :edit }
|
54
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# DELETE <%= route_url %>/1
|
60
|
+
# DELETE <%= route_url %>/1.json
|
61
|
+
def destroy
|
62
|
+
@<%= orm_instance.destroy %>
|
63
|
+
respond_to do |format|
|
64
|
+
format.html { redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %> }
|
65
|
+
format.json { head :no_content }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
# Use callbacks to share common setup or constraints between actions.
|
71
|
+
def set_<%= singular_table_name %>
|
72
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
73
|
+
end
|
74
|
+
|
75
|
+
# Never trust parameters from the scary internet, only allow the white list through.
|
76
|
+
def <%= "#{singular_table_name}_params" %>
|
77
|
+
<%- if attributes_names.empty? -%>
|
78
|
+
params[<%= ":#{singular_table_name}" %>]
|
79
|
+
<%- else -%>
|
80
|
+
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
81
|
+
<%- end -%>
|
82
|
+
end
|
83
|
+
end
|
84
|
+
<% end -%>
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
|
3
|
+
dependency_tracker = false
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'action_view'
|
7
|
+
require 'action_view/dependency_tracker'
|
8
|
+
dependency_tracker = ::ActionView::DependencyTracker
|
9
|
+
rescue LoadError
|
10
|
+
begin
|
11
|
+
require 'cache_digests'
|
12
|
+
dependency_tracker = ::CacheDigests::DependencyTracker
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if dependency_tracker
|
18
|
+
class Jbuilder
|
19
|
+
module DependencyTrackerMethods
|
20
|
+
# Matches:
|
21
|
+
# json.partial! "messages/message"
|
22
|
+
# json.partial!('messages/message')
|
23
|
+
#
|
24
|
+
DIRECT_RENDERS = /
|
25
|
+
\w+\.partial! # json.partial!
|
26
|
+
\(?\s* # optional parenthesis
|
27
|
+
(['"])([^'"]+)\1 # quoted value
|
28
|
+
/x
|
29
|
+
|
30
|
+
# Matches:
|
31
|
+
# json.partial! partial: "comments/comment"
|
32
|
+
# json.comments @post.comments, partial: "comments/comment", as: :comment
|
33
|
+
# json.array! @posts, partial: "posts/post", as: :post
|
34
|
+
# = render partial: "account"
|
35
|
+
#
|
36
|
+
INDIRECT_RENDERS = /
|
37
|
+
(?::partial\s*=>|partial:) # partial: or :partial =>
|
38
|
+
\s* # optional whitespace
|
39
|
+
(['"])([^'"]+)\1 # quoted value
|
40
|
+
/x
|
41
|
+
|
42
|
+
def dependencies
|
43
|
+
direct_dependencies + indirect_dependencies + explicit_dependencies
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def direct_dependencies
|
49
|
+
source.scan(DIRECT_RENDERS).map(&:second)
|
50
|
+
end
|
51
|
+
|
52
|
+
def indirect_dependencies
|
53
|
+
source.scan(INDIRECT_RENDERS).map(&:second)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
::Jbuilder::DependencyTracker = Class.new(dependency_tracker::ERBTracker)
|
59
|
+
::Jbuilder::DependencyTracker.send :include, ::Jbuilder::DependencyTrackerMethods
|
60
|
+
dependency_tracker.register_tracker :jbuilder, ::Jbuilder::DependencyTracker
|
61
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
|
3
|
+
class Jbuilder
|
4
|
+
class NullError < ::NoMethodError
|
5
|
+
def self.build(key)
|
6
|
+
message = "Failed to add #{key.to_s.inspect} property to null object"
|
7
|
+
new(message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ArrayError < ::StandardError
|
12
|
+
def self.build(key)
|
13
|
+
message = "Failed to add #{key.to_s.inspect} property to an array"
|
14
|
+
new(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
require 'action_dispatch/http/mime_type'
|
3
|
+
require 'active_support/cache'
|
4
|
+
|
5
|
+
class JbuilderTemplate < Jbuilder
|
6
|
+
class << self
|
7
|
+
attr_accessor :template_lookup_options
|
8
|
+
end
|
9
|
+
|
10
|
+
self.template_lookup_options = { handlers: [:jbuilder] }
|
11
|
+
|
12
|
+
def initialize(context, *args)
|
13
|
+
@context = context
|
14
|
+
super(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def partial!(name_or_options, locals = {})
|
18
|
+
case name_or_options
|
19
|
+
when ::Hash
|
20
|
+
# partial! partial: 'name', foo: 'bar'
|
21
|
+
options = name_or_options
|
22
|
+
else
|
23
|
+
# partial! 'name', locals: {foo: 'bar'}
|
24
|
+
if locals.one? && (locals.keys.first == :locals)
|
25
|
+
options = locals.merge(partial: name_or_options)
|
26
|
+
else
|
27
|
+
options = { partial: name_or_options, locals: locals }
|
28
|
+
end
|
29
|
+
# partial! 'name', foo: 'bar'
|
30
|
+
as = locals.delete(:as)
|
31
|
+
options[:as] = as if as.present?
|
32
|
+
options[:collection] = locals[:collection] if locals.key?(:collection)
|
33
|
+
end
|
34
|
+
|
35
|
+
_render_partial_with_options options
|
36
|
+
end
|
37
|
+
|
38
|
+
def array!(collection = [], *attributes)
|
39
|
+
options = attributes.extract_options!
|
40
|
+
|
41
|
+
if options.key?(:partial)
|
42
|
+
partial! options[:partial], options.merge(collection: collection)
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Caches the json constructed within the block passed. Has the same signature as the `cache` helper
|
49
|
+
# method in `ActionView::Helpers::CacheHelper` and so can be used in the same way.
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
#
|
53
|
+
# json.cache! ['v1', @person], expires_in: 10.minutes do
|
54
|
+
# json.extract! @person, :name, :age
|
55
|
+
# end
|
56
|
+
def cache!(key=nil, options={})
|
57
|
+
if @context.controller.perform_caching
|
58
|
+
value = ::Rails.cache.fetch(_cache_key(key, options), options) do
|
59
|
+
_scope { yield self }
|
60
|
+
end
|
61
|
+
|
62
|
+
merge! value
|
63
|
+
else
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Conditionally catches the json depending in the condition given as first parameter. Has the same
|
69
|
+
# signature as the `cache` helper method in `ActionView::Helpers::CacheHelper` and so can be used in
|
70
|
+
# the same way.
|
71
|
+
#
|
72
|
+
# Example:
|
73
|
+
#
|
74
|
+
# json.cache_if! !admin?, @person, expires_in: 10.minutes do
|
75
|
+
# json.extract! @person, :name, :age
|
76
|
+
# end
|
77
|
+
def cache_if!(condition, *args)
|
78
|
+
condition ? cache!(*args, &::Proc.new) : yield
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def _render_partial_with_options(options)
|
84
|
+
options.reverse_merge! locals: {}
|
85
|
+
options.reverse_merge! ::JbuilderTemplate.template_lookup_options
|
86
|
+
as = options[:as]
|
87
|
+
|
88
|
+
if as && options.key?(:collection)
|
89
|
+
as = as.to_sym
|
90
|
+
collection = options.delete(:collection)
|
91
|
+
locals = options.delete(:locals)
|
92
|
+
array! collection do |member|
|
93
|
+
member_locals = locals.clone
|
94
|
+
member_locals.merge! collection: collection
|
95
|
+
member_locals.merge! as => member
|
96
|
+
_render_partial options.merge(locals: member_locals)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
_render_partial options
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def _render_partial(options)
|
104
|
+
options[:locals].merge! json: self
|
105
|
+
@context.render options
|
106
|
+
end
|
107
|
+
|
108
|
+
def _cache_key(key, options)
|
109
|
+
key = _fragment_name_with_digest(key, options)
|
110
|
+
key = url_for(key).split('://', 2).last if ::Hash === key
|
111
|
+
::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def _fragment_name_with_digest(key, options)
|
117
|
+
if @context.respond_to?(:cache_fragment_name)
|
118
|
+
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
|
119
|
+
# should be used instead.
|
120
|
+
@context.cache_fragment_name(key, options)
|
121
|
+
elsif @context.respond_to?(:fragment_name_with_digest)
|
122
|
+
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
|
123
|
+
@context.fragment_name_with_digest(key)
|
124
|
+
else
|
125
|
+
key
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def _mapable_arguments?(value, *args)
|
130
|
+
return true if super
|
131
|
+
options = args.last
|
132
|
+
::Hash === options && options.key?(:as)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class JbuilderHandler
|
137
|
+
cattr_accessor :default_format
|
138
|
+
self.default_format = Mime::JSON
|
139
|
+
|
140
|
+
def self.call(template)
|
141
|
+
# this juggling is required to keep line numbers right in the error
|
142
|
+
%{__already_defined = defined?(json); json||=JbuilderTemplate.new(self); #{template.source}
|
143
|
+
json.target! unless (__already_defined && __already_defined != "method")}
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
require 'active_support/core_ext/array'
|
3
|
+
|
4
|
+
class Jbuilder
|
5
|
+
class KeyFormatter
|
6
|
+
def initialize(*args)
|
7
|
+
@format = {}
|
8
|
+
@cache = {}
|
9
|
+
|
10
|
+
options = args.extract_options!
|
11
|
+
args.each do |name|
|
12
|
+
@format[name] = []
|
13
|
+
end
|
14
|
+
options.each do |name, paramaters|
|
15
|
+
@format[name] = paramaters
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize_copy(original)
|
20
|
+
@cache = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def format(key)
|
24
|
+
@cache[key] ||= @format.inject(key.to_s) do |result, args|
|
25
|
+
func, args = args
|
26
|
+
if ::Proc === func
|
27
|
+
func.call result, *args
|
28
|
+
else
|
29
|
+
result.send func, *args
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
require 'jbuilder/jbuilder_template'
|
3
|
+
|
4
|
+
class Jbuilder
|
5
|
+
class Railtie < ::Rails::Railtie
|
6
|
+
initializer :jbuilder do |app|
|
7
|
+
ActiveSupport.on_load :action_view do
|
8
|
+
ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
|
9
|
+
require 'jbuilder/dependency_tracker'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
if Rails::VERSION::MAJOR >= 4
|
14
|
+
generators do |app|
|
15
|
+
Rails::Generators.configure! app.config.generators
|
16
|
+
Rails::Generators.hidden_namespaces.uniq!
|
17
|
+
require 'generators/rails/scaffold_controller_generator'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|