wallaby 4.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/wallaby/application.js +15 -0
- data/app/assets/javascripts/wallaby/form.js +8 -0
- data/app/assets/stylesheets/wallaby/application.scss +51 -0
- data/app/assets/stylesheets/wallaby/base/_functions.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_layout.scss +14 -0
- data/app/assets/stylesheets/wallaby/base/_mixins.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_normalize.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_reset.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_vars.scss +5 -0
- data/app/assets/stylesheets/wallaby/components/_forms.scss +53 -0
- data/app/assets/stylesheets/wallaby/components/_nav.scss +19 -0
- data/app/assets/stylesheets/wallaby/components/_pagination.scss +105 -0
- data/app/assets/stylesheets/wallaby/components/_tables.scss +78 -0
- data/app/assets/stylesheets/wallaby/components/_text.scss +11 -0
- data/app/assets/stylesheets/wallaby/form.scss +11 -0
- data/app/assets/stylesheets/wallaby/summernote.scss.erb +7 -0
- data/app/controllers/wallaby/application_controller.rb +21 -0
- data/app/controllers/wallaby/core_controller.rb +28 -0
- data/app/controllers/wallaby/resources_controller.rb +134 -0
- data/app/controllers/wallaby/secure_controller.rb +42 -0
- data/app/routes/wallaby/resources_router.rb +52 -0
- data/app/security/ability.rb +33 -0
- data/app/views/layouts/wallaby/_footer.html.erb +2 -0
- data/app/views/layouts/wallaby/_header.html.erb +57 -0
- data/app/views/layouts/wallaby/_navs.html.erb +1 -0
- data/app/views/layouts/wallaby/application.html.erb +22 -0
- data/app/views/layouts/wallaby/error.html.erb +20 -0
- data/app/views/wallaby/core/home.html.erb +5 -0
- data/app/views/wallaby/errors/access_denied.html.erb +1 -0
- data/app/views/wallaby/errors/not_authenticated.html.erb +1 -0
- data/app/views/wallaby/errors/not_found.html.erb +6 -0
- data/app/views/wallaby/errors/unprocessable_entity.erb +1 -0
- data/app/views/wallaby/resources/_form.html.erb +12 -0
- data/app/views/wallaby/resources/_index_actions.html.erb +1 -0
- data/app/views/wallaby/resources/_resource_actions.html.erb +3 -0
- data/app/views/wallaby/resources/edit.html.erb +14 -0
- data/app/views/wallaby/resources/form/_belongs_to.html.erb +21 -0
- data/app/views/wallaby/resources/form/_bigint.html.erb +9 -0
- data/app/views/wallaby/resources/form/_binary.html.erb +12 -0
- data/app/views/wallaby/resources/form/_bit.html.erb +9 -0
- data/app/views/wallaby/resources/form/_bit_varying.html.erb +9 -0
- data/app/views/wallaby/resources/form/_boolean.html.erb +14 -0
- data/app/views/wallaby/resources/form/_cidr.html.erb +9 -0
- data/app/views/wallaby/resources/form/_citext.html.erb +21 -0
- data/app/views/wallaby/resources/form/_color.html.erb +20 -0
- data/app/views/wallaby/resources/form/_date.html.erb +29 -0
- data/app/views/wallaby/resources/form/_daterange.html.erb +37 -0
- data/app/views/wallaby/resources/form/_datetime.html.erb +30 -0
- data/app/views/wallaby/resources/form/_decimal.html.erb +9 -0
- data/app/views/wallaby/resources/form/_email.html.erb +5 -0
- data/app/views/wallaby/resources/form/_float.html.erb +9 -0
- data/app/views/wallaby/resources/form/_has_and_belongs_to_many.html.erb +13 -0
- data/app/views/wallaby/resources/form/_has_many.html.erb +13 -0
- data/app/views/wallaby/resources/form/_has_one.html.erb +7 -0
- data/app/views/wallaby/resources/form/_hstore.html.erb +25 -0
- data/app/views/wallaby/resources/form/_inet.html.erb +9 -0
- data/app/views/wallaby/resources/form/_int4range.html.erb +18 -0
- data/app/views/wallaby/resources/form/_int8range.html.erb +18 -0
- data/app/views/wallaby/resources/form/_integer.html.erb +9 -0
- data/app/views/wallaby/resources/form/_json.html.erb +23 -0
- data/app/views/wallaby/resources/form/_jsonb.html.erb +23 -0
- data/app/views/wallaby/resources/form/_ltree.html.erb +5 -0
- data/app/views/wallaby/resources/form/_macaddr.html.erb +9 -0
- data/app/views/wallaby/resources/form/_money.html.erb +12 -0
- data/app/views/wallaby/resources/form/_numrange.html.erb +18 -0
- data/app/views/wallaby/resources/form/_password.html.erb +5 -0
- data/app/views/wallaby/resources/form/_point.html.erb +18 -0
- data/app/views/wallaby/resources/form/_string.html.erb +5 -0
- data/app/views/wallaby/resources/form/_text.html.erb +21 -0
- data/app/views/wallaby/resources/form/_time.html.erb +29 -0
- data/app/views/wallaby/resources/form/_tsrange.html.erb +38 -0
- data/app/views/wallaby/resources/form/_tstzrange.html.erb +38 -0
- data/app/views/wallaby/resources/form/_tsvector.html.erb +5 -0
- data/app/views/wallaby/resources/form/_uuid.html.erb +9 -0
- data/app/views/wallaby/resources/form/_xml.html.erb +23 -0
- data/app/views/wallaby/resources/index/_belongs_to.html.erb +1 -0
- data/app/views/wallaby/resources/index/_bigint.html.erb +1 -0
- data/app/views/wallaby/resources/index/_binary.html.erb +1 -0
- data/app/views/wallaby/resources/index/_bit.html.erb +5 -0
- data/app/views/wallaby/resources/index/_bit_varying.html.erb +5 -0
- data/app/views/wallaby/resources/index/_boolean.html.erb +5 -0
- data/app/views/wallaby/resources/index/_cidr.html.erb +6 -0
- data/app/views/wallaby/resources/index/_citext.html.erb +12 -0
- data/app/views/wallaby/resources/index/_color.html.erb +5 -0
- data/app/views/wallaby/resources/index/_date.html.erb +7 -0
- data/app/views/wallaby/resources/index/_daterange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_datetime.html.erb +7 -0
- data/app/views/wallaby/resources/index/_decimal.html.erb +1 -0
- data/app/views/wallaby/resources/index/_email.html.erb +1 -0
- data/app/views/wallaby/resources/index/_float.html.erb +1 -0
- data/app/views/wallaby/resources/index/_has_and_belongs_to_many.html.erb +11 -0
- data/app/views/wallaby/resources/index/_has_many.html.erb +11 -0
- data/app/views/wallaby/resources/index/_has_one.html.erb +1 -0
- data/app/views/wallaby/resources/index/_hstore.html.erb +12 -0
- data/app/views/wallaby/resources/index/_inet.html.erb +6 -0
- data/app/views/wallaby/resources/index/_int4range.html.erb +7 -0
- data/app/views/wallaby/resources/index/_int8range.html.erb +7 -0
- data/app/views/wallaby/resources/index/_integer.html.erb +1 -0
- data/app/views/wallaby/resources/index/_json.html.erb +12 -0
- data/app/views/wallaby/resources/index/_jsonb.html.erb +12 -0
- data/app/views/wallaby/resources/index/_ltree.html.erb +12 -0
- data/app/views/wallaby/resources/index/_macaddr.html.erb +5 -0
- data/app/views/wallaby/resources/index/_money.html.erb +1 -0
- data/app/views/wallaby/resources/index/_numrange.html.erb +7 -0
- data/app/views/wallaby/resources/index/_point.html.erb +6 -0
- data/app/views/wallaby/resources/index/_string.html.erb +12 -0
- data/app/views/wallaby/resources/index/_text.html.erb +12 -0
- data/app/views/wallaby/resources/index/_time.html.erb +6 -0
- data/app/views/wallaby/resources/index/_tsrange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_tstzrange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_tsvector.html.erb +12 -0
- data/app/views/wallaby/resources/index/_uuid.html.erb +12 -0
- data/app/views/wallaby/resources/index/_xml.html.erb +12 -0
- data/app/views/wallaby/resources/index.html.erb +66 -0
- data/app/views/wallaby/resources/new.html.erb +14 -0
- data/app/views/wallaby/resources/shared/_resource_nav.html.erb +29 -0
- data/app/views/wallaby/resources/show/_belongs_to.html.erb +7 -0
- data/app/views/wallaby/resources/show/_bigint.html.erb +1 -0
- data/app/views/wallaby/resources/show/_binary.html.erb +1 -0
- data/app/views/wallaby/resources/show/_bit.html.erb +5 -0
- data/app/views/wallaby/resources/show/_bit_varying.html.erb +5 -0
- data/app/views/wallaby/resources/show/_boolean.html.erb +5 -0
- data/app/views/wallaby/resources/show/_cidr.html.erb +6 -0
- data/app/views/wallaby/resources/show/_citext.html.erb +1 -0
- data/app/views/wallaby/resources/show/_color.html.erb +5 -0
- data/app/views/wallaby/resources/show/_date.html.erb +7 -0
- data/app/views/wallaby/resources/show/_daterange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_datetime.html.erb +6 -0
- data/app/views/wallaby/resources/show/_decimal.html.erb +1 -0
- data/app/views/wallaby/resources/show/_email.html.erb +1 -0
- data/app/views/wallaby/resources/show/_float.html.erb +1 -0
- data/app/views/wallaby/resources/show/_has_and_belongs_to_many.html.erb +5 -0
- data/app/views/wallaby/resources/show/_has_many.html.erb +5 -0
- data/app/views/wallaby/resources/show/_has_one.html.erb +1 -0
- data/app/views/wallaby/resources/show/_hstore.html.erb +5 -0
- data/app/views/wallaby/resources/show/_inet.html.erb +6 -0
- data/app/views/wallaby/resources/show/_int4range.html.erb +7 -0
- data/app/views/wallaby/resources/show/_int8range.html.erb +7 -0
- data/app/views/wallaby/resources/show/_integer.html.erb +1 -0
- data/app/views/wallaby/resources/show/_json.html.erb +5 -0
- data/app/views/wallaby/resources/show/_jsonb.html.erb +5 -0
- data/app/views/wallaby/resources/show/_ltree.html.erb +1 -0
- data/app/views/wallaby/resources/show/_macaddr.html.erb +5 -0
- data/app/views/wallaby/resources/show/_money.html.erb +1 -0
- data/app/views/wallaby/resources/show/_numrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_point.html.erb +6 -0
- data/app/views/wallaby/resources/show/_string.html.erb +1 -0
- data/app/views/wallaby/resources/show/_text.html.erb +1 -0
- data/app/views/wallaby/resources/show/_time.html.erb +6 -0
- data/app/views/wallaby/resources/show/_tsrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_tstzrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_tsvector.html.erb +1 -0
- data/app/views/wallaby/resources/show/_uuid.html.erb +5 -0
- data/app/views/wallaby/resources/show/_xml.html.erb +5 -0
- data/app/views/wallaby/resources/show.html.erb +31 -0
- data/app/views/wallaby/shared/_flash_messages.html.erb +13 -0
- data/config/locales/en.yml +29 -0
- data/config/routes.rb +34 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +105 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +18 -0
- data/lib/adaptors/wallaby/active_record/model_decorator.rb +81 -0
- data/lib/adaptors/wallaby/active_record/model_finder.rb +12 -0
- data/lib/adaptors/wallaby/active_record/model_operator/normalizer.rb +44 -0
- data/lib/adaptors/wallaby/active_record/model_operator/permitter.rb +50 -0
- data/lib/adaptors/wallaby/active_record/model_operator/querier.rb +47 -0
- data/lib/adaptors/wallaby/active_record/model_operator/validator.rb +16 -0
- data/lib/adaptors/wallaby/active_record/model_operator.rb +82 -0
- data/lib/adaptors/wallaby/active_record.rb +2 -0
- data/lib/decorators/wallaby/resource_decorator.rb +78 -0
- data/lib/errors/wallaby/deprecated.rb +4 -0
- data/lib/errors/wallaby/general_error.rb +4 -0
- data/lib/errors/wallaby/invalid_error.rb +4 -0
- data/lib/errors/wallaby/model_not_found.rb +4 -0
- data/lib/errors/wallaby/not_authenticated.rb +4 -0
- data/lib/errors/wallaby/not_implemented.rb +4 -0
- data/lib/errors/wallaby/operation_not_found.rb +4 -0
- data/lib/errors/wallaby/resource_not_found.rb +4 -0
- data/lib/forms/wallaby/form_builder.rb +30 -0
- data/lib/handlers/wallaby/cached_compiled_erb.rb +14 -0
- data/lib/helpers/wallaby/application_helper.rb +30 -0
- data/lib/helpers/wallaby/core_helper.rb +50 -0
- data/lib/helpers/wallaby/form_helper.rb +21 -0
- data/lib/helpers/wallaby/links_helper.rb +83 -0
- data/lib/helpers/wallaby/paginatable_helper.rb +9 -0
- data/lib/helpers/wallaby/resources_helper.rb +55 -0
- data/lib/helpers/wallaby/secure_helper.rb +25 -0
- data/lib/helpers/wallaby/sorting_helper.rb +43 -0
- data/lib/helpers/wallaby/styling_helper.rb +57 -0
- data/lib/interfaces/wallaby/mode.rb +18 -0
- data/lib/interfaces/wallaby/model_decorator.rb +58 -0
- data/lib/interfaces/wallaby/model_finder.rb +5 -0
- data/lib/interfaces/wallaby/model_operator.rb +31 -0
- data/lib/services/wallaby/decorator_finder.rb +16 -0
- data/lib/services/wallaby/lookup_context_wrapper.rb +40 -0
- data/lib/services/wallaby/map.rb +53 -0
- data/lib/services/wallaby/model_servicer.rb +38 -0
- data/lib/services/wallaby/servicer_finder.rb +5 -0
- data/lib/tasks/wallaby_tasks.rake +4 -0
- data/lib/utils/wallaby/utils.rb +31 -0
- data/lib/wallaby/configuration/models.rb +17 -0
- data/lib/wallaby/configuration/security.rb +30 -0
- data/lib/wallaby/configuration.rb +49 -0
- data/lib/wallaby/engine.rb +89 -0
- data/lib/wallaby/version.rb +3 -0
- data/lib/wallaby.rb +5 -0
- metadata +459 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
module Wallaby::LinksHelper
|
2
|
+
def index_path(model_class = nil, extra_params = nil)
|
3
|
+
model_class ||= current_model_class
|
4
|
+
extra_params ||= {}
|
5
|
+
wallaby_engine.resources_path to_resources_name(model_class), extra_params
|
6
|
+
end
|
7
|
+
|
8
|
+
def new_path(model_class = nil)
|
9
|
+
model_class ||= current_model_class
|
10
|
+
wallaby_engine.new_resource_path to_resources_name model_class
|
11
|
+
end
|
12
|
+
|
13
|
+
def show_path(resource)
|
14
|
+
decorated = decorate resource
|
15
|
+
wallaby_engine.resource_path decorated.resources_name, decorated.primary_key_value
|
16
|
+
end
|
17
|
+
|
18
|
+
def edit_path(resource)
|
19
|
+
decorated = decorate resource
|
20
|
+
wallaby_engine.edit_resource_path decorated.resources_name, decorated.primary_key_value
|
21
|
+
end
|
22
|
+
|
23
|
+
def index_link(model_class = nil, html_options = {}, &block)
|
24
|
+
model_class ||= current_model_class
|
25
|
+
return if cannot? :index, model_class
|
26
|
+
block ||= -> { to_model_label model_class }
|
27
|
+
|
28
|
+
link_to index_path(model_class, html_options.delete(:extra_params)), html_options, &block
|
29
|
+
end
|
30
|
+
|
31
|
+
def new_link(model_class = nil, html_options = {}, &block)
|
32
|
+
model_class ||= current_model_class
|
33
|
+
return if cannot? :new, model_class
|
34
|
+
|
35
|
+
block ||= -> { "#{ ct 'link.new' } #{ to_model_label model_class }" }
|
36
|
+
html_options[:class] = 'text-success' unless html_options.has_key? :class
|
37
|
+
|
38
|
+
prepend_if html_options
|
39
|
+
link_to new_path(model_class), html_options, &block
|
40
|
+
end
|
41
|
+
|
42
|
+
def show_link(resource, html_options = {}, &block)
|
43
|
+
return if cannot? :show, extract(resource)
|
44
|
+
|
45
|
+
# NOTE: to_s is a must
|
46
|
+
# if a block is returning integer (e.g. `{ 1 }`)
|
47
|
+
# `link_to` will render blank text note inside hyper link
|
48
|
+
block ||= -> { decorate(resource).to_label.to_s }
|
49
|
+
|
50
|
+
link_to show_path(resource), html_options, &block
|
51
|
+
end
|
52
|
+
|
53
|
+
def edit_link(resource, html_options = {}, &block)
|
54
|
+
return if cannot? :edit, extract(resource)
|
55
|
+
|
56
|
+
block ||= -> { "#{ ct 'link.edit' } #{ decorate(resource).to_label }" }
|
57
|
+
html_options[:class] = 'text-warning' unless html_options.has_key? :class
|
58
|
+
|
59
|
+
link_to edit_path(resource), html_options, &block
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete_link(resource, html_options = {}, &block)
|
63
|
+
return if cannot? :destroy, extract(resource)
|
64
|
+
|
65
|
+
block ||= -> { ct 'link.delete' }
|
66
|
+
html_options[:class] = 'text-danger' unless html_options.has_key? :class
|
67
|
+
html_options[:method] ||= :delete
|
68
|
+
html_options[:data] ||= {}
|
69
|
+
html_options[:data][:confirm] ||= ct('link.confirm.delete')
|
70
|
+
|
71
|
+
link_to show_path(resource), html_options, &block
|
72
|
+
end
|
73
|
+
|
74
|
+
def cancel_link(html_options = {}, &block)
|
75
|
+
block ||= -> { ct 'link.cancel' }
|
76
|
+
link_to :back, html_options, &block
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepend_if(html_options = {})
|
80
|
+
prepend = html_options.delete :prepend
|
81
|
+
concat "#{ prepend } " if prepend.present?
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Wallaby::PaginatableHelper
|
2
|
+
def paginatable?(collection)
|
3
|
+
defined?(Kaminari) && collection.present? && collection.respond_to?(:total_pages)
|
4
|
+
end
|
5
|
+
|
6
|
+
def custom_pagination_stats(collection)
|
7
|
+
"Showing #{ content_tag :b, collection.size }".html_safe
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Wallaby::ResourcesHelper
|
2
|
+
include Wallaby::FormHelper
|
3
|
+
include Wallaby::SortingHelper
|
4
|
+
include Wallaby::PaginatableHelper
|
5
|
+
|
6
|
+
def decorate(resource)
|
7
|
+
if resource.respond_to? :map # collection
|
8
|
+
decorator = Wallaby::DecoratorFinder.find_resource resource.first.class
|
9
|
+
resource.map do |item|
|
10
|
+
decorator.decorate item
|
11
|
+
end
|
12
|
+
else
|
13
|
+
decorator = Wallaby::DecoratorFinder.find_resource resource.class
|
14
|
+
decorator.decorate resource
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def extract(resource)
|
19
|
+
if resource.is_a? Wallaby::ResourceDecorator
|
20
|
+
resource.resource
|
21
|
+
else
|
22
|
+
resource
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def model_decorator(model_class)
|
27
|
+
Wallaby::DecoratorFinder.find_model model_class
|
28
|
+
end
|
29
|
+
|
30
|
+
def model_servicer(model_decorator)
|
31
|
+
model_class = model_decorator.model_class
|
32
|
+
Wallaby::ServicerFinder.find(model_class).new model_class, model_decorator
|
33
|
+
end
|
34
|
+
|
35
|
+
def type_partial_render(options = {}, locals = {}, metadata_method = :show_metadata_of, &block)
|
36
|
+
decorated = locals[:object]
|
37
|
+
field_name = locals[:field_name].to_s
|
38
|
+
|
39
|
+
fail ArgumentError unless field_name.present? && decorated.is_a?(Wallaby::ResourceDecorator)
|
40
|
+
|
41
|
+
locals[:metadata] = decorated.send metadata_method, field_name
|
42
|
+
locals[:value] = decorated.public_send field_name
|
43
|
+
|
44
|
+
render(options, locals, &block) or render('string', locals, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def index_type_partial_render(options = {}, locals = {}, &block)
|
48
|
+
type_partial_render options, locals, :index_metadata_of
|
49
|
+
end
|
50
|
+
|
51
|
+
def show_title(decorated)
|
52
|
+
fail ArgumentError unless decorated.is_a? Wallaby::ResourceDecorator
|
53
|
+
[ to_model_label(decorated.model_class), decorated.to_label ].compact.join ': '
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Wallaby::SecureHelper
|
2
|
+
def user_portrait(user = current_user)
|
3
|
+
if user.respond_to? :email
|
4
|
+
image_source = "http#{ request.ssl? ? 's' : '' }://www.gravatar.com/avatar/#{ Digest::MD5.hexdigest user.email.downcase }"
|
5
|
+
image_tag image_source, class: 'hidden-xs user-portrait'
|
6
|
+
else
|
7
|
+
content_tag :i, nil, class: 'glyphicon glyphicon-user user-portrait'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def logout_path(user = current_user, app = main_app)
|
12
|
+
path = if defined? Devise
|
13
|
+
scope = Devise::Mapping.find_scope! user
|
14
|
+
"destroy_#{ scope }_session_path"
|
15
|
+
else
|
16
|
+
'logout_path'
|
17
|
+
end
|
18
|
+
app.public_send path if app.respond_to? path
|
19
|
+
end
|
20
|
+
|
21
|
+
def logout_method
|
22
|
+
method = Array(Devise.sign_out_via).first if defined? Devise
|
23
|
+
method || :delete
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Wallaby::SortingHelper
|
2
|
+
def sort_link(field_name, model_decorator = current_model_decorator)
|
3
|
+
metadata = model_decorator.index_metadata_of field_name
|
4
|
+
|
5
|
+
if metadata[:is_origin] && !metadata[:is_association] || metadata[:sort_field_name]
|
6
|
+
sort_field_name = metadata[:sort_field_name] || field_name
|
7
|
+
extra_params = next_sort_param sort_field_name
|
8
|
+
index_link(model_decorator.model_class, extra_params: extra_params) { metadata[:label] }
|
9
|
+
else
|
10
|
+
metadata[:label]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sort_hash
|
15
|
+
@sort_hash ||= begin
|
16
|
+
array = params[:sort].to_s.split(%r(\s*,\s*)).map{ |v| v.split %r(\s+) }
|
17
|
+
Wallaby::Utils.to_hash array
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def next_sort_param(field_name)
|
22
|
+
field_name = field_name.to_s
|
23
|
+
orders = [ 'asc', 'desc', nil ]
|
24
|
+
clean_params.tap do |hash|
|
25
|
+
sortings = sort_hash.dup
|
26
|
+
next_index = (orders.index(sortings[field_name]) + 1) % orders.length
|
27
|
+
if orders[next_index].nil?
|
28
|
+
sortings.delete field_name
|
29
|
+
else
|
30
|
+
sortings[field_name] = orders[next_index]
|
31
|
+
end
|
32
|
+
if sortings.present?
|
33
|
+
hash[:sort] = sortings.to_a.map{ |v| v.join ' ' }.join ','
|
34
|
+
else
|
35
|
+
hash.delete :sort
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def sort_class(field_name)
|
41
|
+
sort_hash[ field_name.to_s ]
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Wallaby::StylingHelper
|
2
|
+
def icon(icon_suffix, html_options = {}, &block)
|
3
|
+
html_options[:class] = Array html_options[:class]
|
4
|
+
html_options[:class] << "glyphicon glyphicon-#{ icon_suffix }"
|
5
|
+
|
6
|
+
content_tag :i, nil, html_options, &block
|
7
|
+
end
|
8
|
+
|
9
|
+
def itooltip(title, icon_suffix = 'info-sign', html_options = {})
|
10
|
+
html_options[:title] = title
|
11
|
+
(html_options[:data] ||= {}).merge! toggle: "tooltip", placement: "top"
|
12
|
+
|
13
|
+
icon icon_suffix, html_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def ilink_to(options = nil, html_options = {})
|
17
|
+
icon_suffix = html_options.delete(:icon) || 'info-sign'
|
18
|
+
link_to options, html_options do
|
19
|
+
icon icon_suffix
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def imodal(title, body, html_options = {})
|
24
|
+
uuid = random_uuid
|
25
|
+
label ||= html_options.delete(:label) ||
|
26
|
+
html_options.delete(:icon) ||
|
27
|
+
icon('circle-arrow-up')
|
28
|
+
link_to(label, 'javascript:;', data: { toggle: 'modal', target: "##{ uuid }" }) +
|
29
|
+
content_tag(:div, id: uuid, class: 'modal fade', tabindex: -1, role: 'dialog') do
|
30
|
+
content_tag :div, class: 'modal-dialog modal-lg' do
|
31
|
+
content_tag :div, class: 'modal-content' do
|
32
|
+
content_tag(:div, class: 'modal-header') do
|
33
|
+
button_tag(type: 'button', class: 'close', data: { dismiss: 'modal' }, aria: { label: 'Close' }) do
|
34
|
+
content_tag :span, raw('×'), aria: { hidden: true }
|
35
|
+
end +
|
36
|
+
content_tag(:h4, title, class: 'modal-title')
|
37
|
+
end +
|
38
|
+
content_tag(:div, class: 'modal-body') do
|
39
|
+
body
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def null
|
47
|
+
muted 'null'
|
48
|
+
end
|
49
|
+
|
50
|
+
def na
|
51
|
+
muted 'n/a'
|
52
|
+
end
|
53
|
+
|
54
|
+
def muted(content)
|
55
|
+
content_tag :i, "<#{ content }>", class: 'text-muted'
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Wallaby::Mode
|
2
|
+
INTERFACE_METHODS = %w( model_decorator model_finder model_operator )
|
3
|
+
|
4
|
+
INTERFACE_METHODS.each do |method_id|
|
5
|
+
define_singleton_method method_id do
|
6
|
+
begin
|
7
|
+
method_class = __callee__.to_s.classify
|
8
|
+
class_name = "#{ name }::#{ method_class }"
|
9
|
+
parent_class = "Wallaby::#{ method_class }".constantize
|
10
|
+
class_name.constantize.tap do |klass|
|
11
|
+
fail Wallaby::InvalidError, "#{ klass } must inherit #{ parent_class }" unless klass < parent_class
|
12
|
+
end
|
13
|
+
rescue NameError
|
14
|
+
fail Wallaby::NotImplemented, class_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Wallaby::ModelDecorator
|
2
|
+
attr_reader :model_class
|
3
|
+
|
4
|
+
def initialize(model_class)
|
5
|
+
@model_class = model_class
|
6
|
+
end
|
7
|
+
|
8
|
+
[ '', 'index_', 'show_', 'form_' ].each do |prefix|
|
9
|
+
class_eval <<-RUBY
|
10
|
+
def #{ prefix }fields
|
11
|
+
fail Wallaby::NotImplemented
|
12
|
+
end
|
13
|
+
|
14
|
+
def #{ prefix }fields=(#{ prefix }fields)
|
15
|
+
@#{ prefix }fields = #{ prefix }fields.with_indifferent_access
|
16
|
+
end
|
17
|
+
|
18
|
+
def #{ prefix }field_names
|
19
|
+
@#{ prefix }field_names ||= #{ prefix }fields.keys.tap do |names|
|
20
|
+
names.delete primary_key
|
21
|
+
names.unshift primary_key
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def #{ prefix }field_names=(#{ prefix }field_names)
|
26
|
+
@#{ prefix }field_names = #{ prefix }field_names
|
27
|
+
end
|
28
|
+
|
29
|
+
def #{ prefix }metadata_of(field_name)
|
30
|
+
#{ prefix }fields[field_name] || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def #{ prefix }label_of(field_name)
|
34
|
+
#{ prefix }metadata_of(field_name)[:label]
|
35
|
+
end
|
36
|
+
|
37
|
+
def #{ prefix }type_of(field_name)
|
38
|
+
#{ prefix }metadata_of(field_name)[:type]
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
end
|
42
|
+
|
43
|
+
def form_active_errors(resource)
|
44
|
+
fail Wallaby::NotImplemented
|
45
|
+
end
|
46
|
+
|
47
|
+
def primary_key
|
48
|
+
fail Wallaby::NotImplemented
|
49
|
+
end
|
50
|
+
|
51
|
+
def guess_title(resource)
|
52
|
+
fail Wallaby::NotImplemented
|
53
|
+
end
|
54
|
+
|
55
|
+
def resources_name
|
56
|
+
Wallaby::Utils.to_resources_name @model_class
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Wallaby::ModelOperator
|
2
|
+
def initialize(model_class, model_decorator = nil)
|
3
|
+
fail ArgumentError, 'model class required' unless model_class
|
4
|
+
@model_class = model_class
|
5
|
+
@model_decorator = model_decorator || Wallaby::DecoratorFinder.find_model(@model_class)
|
6
|
+
end
|
7
|
+
|
8
|
+
def collection(params, ability)
|
9
|
+
fail Wallaby::NotImplemented
|
10
|
+
end
|
11
|
+
|
12
|
+
def new(params)
|
13
|
+
fail Wallaby::NotImplemented
|
14
|
+
end
|
15
|
+
|
16
|
+
def find(id, params)
|
17
|
+
fail Wallaby::NotImplemented
|
18
|
+
end
|
19
|
+
|
20
|
+
def create(params, ability)
|
21
|
+
fail Wallaby::NotImplemented
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(resource, params, ability)
|
25
|
+
fail Wallaby::NotImplemented
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy(resource, params)
|
29
|
+
fail Wallaby::NotImplemented
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Wallaby::DecoratorFinder
|
2
|
+
DEFAULT_DECORATOR = Wallaby::ResourceDecorator
|
3
|
+
|
4
|
+
def self.find_model(model_class)
|
5
|
+
Wallaby::Map.decorator_map[model_class] || new_model(model_class)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.find_resource(model_class)
|
9
|
+
Wallaby::Map.decorator_map[model_class] || DEFAULT_DECORATOR
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_model(model_class)
|
13
|
+
mode = Wallaby::ActiveRecord
|
14
|
+
mode.model_decorator.new model_class
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Wallaby::LookupContextWrapper
|
2
|
+
delegate *begin # origin methods
|
3
|
+
ActionView::LookupContext.instance_methods \
|
4
|
+
- Object.instance_methods - %i( find_template )
|
5
|
+
end, to: :@lookup_context
|
6
|
+
|
7
|
+
def initialize(lookup_context)
|
8
|
+
@lookup_context = lookup_context
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_template(*args)
|
12
|
+
key = args.join '/'
|
13
|
+
caching key do
|
14
|
+
@lookup_context.find_template *args
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def caching(key)
|
20
|
+
@templates ||= {}
|
21
|
+
unless @templates.has_key? key
|
22
|
+
@templates[key] = begin
|
23
|
+
yield
|
24
|
+
rescue ActionView::MissingTemplate
|
25
|
+
raise if Rails.env.development?
|
26
|
+
BlankTemplate.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@templates[key]
|
30
|
+
end
|
31
|
+
|
32
|
+
class BlankTemplate < ActionView::Template::HTML
|
33
|
+
def initialize
|
34
|
+
super nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def render(*args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Wallaby::Map
|
2
|
+
def self.mode_map(modes = nil)
|
3
|
+
Rails.cache.fetch 'wallaby/map/mode_map' do
|
4
|
+
{}.tap do |map|
|
5
|
+
(modes || Wallaby::Mode.subclasses).each do |mode_class|
|
6
|
+
mode_class.model_finder.new.all.each do |model_class|
|
7
|
+
map[model_class] = mode_class
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.model_classes(configuration = nil)
|
15
|
+
Rails.cache.fetch 'wallaby/map/model_classes' do
|
16
|
+
models = (configuration || Wallaby.configuration).models
|
17
|
+
full_list = mode_map.keys
|
18
|
+
configed_models = models.presence
|
19
|
+
|
20
|
+
return full_list - models.excludes unless configed_models
|
21
|
+
|
22
|
+
invalid_models = configed_models - full_list
|
23
|
+
if invalid_models.length > 0
|
24
|
+
fail Wallaby::InvalidError, "#{ invalid_models.to_sentence } are invalid models."
|
25
|
+
end
|
26
|
+
configed_models
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.controller_map
|
31
|
+
model_class_map Wallaby::ResourcesController, __callee__
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.decorator_map
|
35
|
+
model_class_map Wallaby::ResourceDecorator, __callee__
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.servicer_map
|
39
|
+
model_class_map Wallaby::ModelServicer, __callee__
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.model_class_map(base_class, method_id)
|
43
|
+
Rails.cache.fetch "wallaby/map/#{ method_id }" do
|
44
|
+
{}.tap do |map|
|
45
|
+
base_class.subclasses
|
46
|
+
.reject{ |klass| klass.name.blank? }
|
47
|
+
.each do |klass|
|
48
|
+
map[klass.model_class] = klass
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Wallaby::ModelServicer
|
2
|
+
def self.model_class
|
3
|
+
if self < Wallaby::ModelServicer
|
4
|
+
Wallaby::Utils.to_model_class name.gsub('Servicer', ''), name
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(model_class = nil, model_decorator = nil)
|
9
|
+
@model_class = model_class || self.class.model_class
|
10
|
+
fail ArgumentError, 'model class required' unless @model_class
|
11
|
+
@model_decorator = model_decorator || Wallaby::DecoratorFinder.find_model(@model_class)
|
12
|
+
@delegator = Wallaby.adaptor.model_operator.new @model_class, @model_decorator
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection(params, ability)
|
16
|
+
@delegator.collection params, ability
|
17
|
+
end
|
18
|
+
|
19
|
+
def new(params)
|
20
|
+
@delegator.new params
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(id, params)
|
24
|
+
@delegator.find id, params
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(params, ability)
|
28
|
+
@delegator.create params, ability
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(resource, params, ability)
|
32
|
+
@delegator.update resource, params, ability
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy(resource, params)
|
36
|
+
@delegator.destroy resource, params
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Wallaby::Utils
|
2
|
+
def self.to_resources_name(model_class)
|
3
|
+
return '' if model_class.blank?
|
4
|
+
model_class.to_s.underscore.gsub('/', '::').pluralize
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.to_model_label(model_class)
|
8
|
+
model_class_name = to_model_name model_class
|
9
|
+
model_class_name.titleize.gsub '/', ' / '
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.to_model_name(resources_name)
|
13
|
+
return '' if resources_name.blank?
|
14
|
+
resources_name.to_s.singularize.gsub('::', '/').camelize
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.to_model_class(resources_name, source = nil)
|
18
|
+
return if resources_name.blank?
|
19
|
+
begin
|
20
|
+
class_name = to_model_name resources_name
|
21
|
+
class_name.constantize
|
22
|
+
rescue
|
23
|
+
message = [ class_name, source ].compact.join(' from ')
|
24
|
+
fail Wallaby::ModelNotFound, message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_hash(array)
|
29
|
+
Hash[ *array.flatten(1) ]
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Wallaby::Configuration::Security
|
2
|
+
# by default, current_user returns nil
|
3
|
+
DEFAULT_CURRENT_USER = -> {}
|
4
|
+
# by default, authenticate returns true not to stop the before_action chain
|
5
|
+
DEFAULT_AUTHENTICATE = -> { true }
|
6
|
+
|
7
|
+
def current_user(&block)
|
8
|
+
if block_given?
|
9
|
+
@current_user = block
|
10
|
+
else
|
11
|
+
@current_user ||= DEFAULT_CURRENT_USER
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_user?
|
16
|
+
current_user != DEFAULT_CURRENT_USER
|
17
|
+
end
|
18
|
+
|
19
|
+
def authenticate(&block)
|
20
|
+
if block_given?
|
21
|
+
@authenticate = block
|
22
|
+
else
|
23
|
+
@authenticate ||= DEFAULT_AUTHENTICATE
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def authenticate?
|
28
|
+
authenticate != DEFAULT_AUTHENTICATE
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Wallaby
|
2
|
+
class Configuration
|
3
|
+
def adaptor
|
4
|
+
@adaptor ||= Wallaby::ActiveRecord
|
5
|
+
end
|
6
|
+
|
7
|
+
def adaptor=(adaptor)
|
8
|
+
if @adaptor
|
9
|
+
fail 'Adaptor has been initialized. Please place adaptor assignment at the top of configuration.'
|
10
|
+
end
|
11
|
+
@adaptor = adaptor
|
12
|
+
end
|
13
|
+
|
14
|
+
def models
|
15
|
+
@models ||= Models.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def models=(models)
|
19
|
+
self.models.set models
|
20
|
+
end
|
21
|
+
|
22
|
+
def security
|
23
|
+
@security ||= Security.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_controller
|
27
|
+
@base_controller ||= ::ApplicationController
|
28
|
+
end
|
29
|
+
|
30
|
+
def base_controller=(base_controller)
|
31
|
+
@base_controller = base_controller
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.configuration
|
36
|
+
@configuration ||= Configuration.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.config
|
40
|
+
yield configuration
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.adaptor
|
44
|
+
configuration.adaptor
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'wallaby/configuration/models'
|
49
|
+
require 'wallaby/configuration/security'
|