wallaby 4.1.6

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.
Files changed (209) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +29 -0
  4. data/app/assets/javascripts/wallaby/application.js +15 -0
  5. data/app/assets/javascripts/wallaby/form.js +8 -0
  6. data/app/assets/stylesheets/wallaby/application.scss +51 -0
  7. data/app/assets/stylesheets/wallaby/base/_functions.scss +0 -0
  8. data/app/assets/stylesheets/wallaby/base/_layout.scss +14 -0
  9. data/app/assets/stylesheets/wallaby/base/_mixins.scss +0 -0
  10. data/app/assets/stylesheets/wallaby/base/_normalize.scss +0 -0
  11. data/app/assets/stylesheets/wallaby/base/_reset.scss +0 -0
  12. data/app/assets/stylesheets/wallaby/base/_vars.scss +5 -0
  13. data/app/assets/stylesheets/wallaby/components/_forms.scss +53 -0
  14. data/app/assets/stylesheets/wallaby/components/_nav.scss +19 -0
  15. data/app/assets/stylesheets/wallaby/components/_pagination.scss +105 -0
  16. data/app/assets/stylesheets/wallaby/components/_tables.scss +78 -0
  17. data/app/assets/stylesheets/wallaby/components/_text.scss +11 -0
  18. data/app/assets/stylesheets/wallaby/form.scss +11 -0
  19. data/app/assets/stylesheets/wallaby/summernote.scss.erb +7 -0
  20. data/app/controllers/wallaby/application_controller.rb +21 -0
  21. data/app/controllers/wallaby/core_controller.rb +28 -0
  22. data/app/controllers/wallaby/resources_controller.rb +134 -0
  23. data/app/controllers/wallaby/secure_controller.rb +42 -0
  24. data/app/routes/wallaby/resources_router.rb +52 -0
  25. data/app/security/ability.rb +33 -0
  26. data/app/views/layouts/wallaby/_footer.html.erb +2 -0
  27. data/app/views/layouts/wallaby/_header.html.erb +57 -0
  28. data/app/views/layouts/wallaby/_navs.html.erb +1 -0
  29. data/app/views/layouts/wallaby/application.html.erb +22 -0
  30. data/app/views/layouts/wallaby/error.html.erb +20 -0
  31. data/app/views/wallaby/core/home.html.erb +5 -0
  32. data/app/views/wallaby/errors/access_denied.html.erb +1 -0
  33. data/app/views/wallaby/errors/not_authenticated.html.erb +1 -0
  34. data/app/views/wallaby/errors/not_found.html.erb +6 -0
  35. data/app/views/wallaby/errors/unprocessable_entity.erb +1 -0
  36. data/app/views/wallaby/resources/_form.html.erb +12 -0
  37. data/app/views/wallaby/resources/_index_actions.html.erb +1 -0
  38. data/app/views/wallaby/resources/_resource_actions.html.erb +3 -0
  39. data/app/views/wallaby/resources/edit.html.erb +14 -0
  40. data/app/views/wallaby/resources/form/_belongs_to.html.erb +21 -0
  41. data/app/views/wallaby/resources/form/_bigint.html.erb +9 -0
  42. data/app/views/wallaby/resources/form/_binary.html.erb +12 -0
  43. data/app/views/wallaby/resources/form/_bit.html.erb +9 -0
  44. data/app/views/wallaby/resources/form/_bit_varying.html.erb +9 -0
  45. data/app/views/wallaby/resources/form/_boolean.html.erb +14 -0
  46. data/app/views/wallaby/resources/form/_cidr.html.erb +9 -0
  47. data/app/views/wallaby/resources/form/_citext.html.erb +21 -0
  48. data/app/views/wallaby/resources/form/_color.html.erb +20 -0
  49. data/app/views/wallaby/resources/form/_date.html.erb +29 -0
  50. data/app/views/wallaby/resources/form/_daterange.html.erb +37 -0
  51. data/app/views/wallaby/resources/form/_datetime.html.erb +30 -0
  52. data/app/views/wallaby/resources/form/_decimal.html.erb +9 -0
  53. data/app/views/wallaby/resources/form/_email.html.erb +5 -0
  54. data/app/views/wallaby/resources/form/_float.html.erb +9 -0
  55. data/app/views/wallaby/resources/form/_has_and_belongs_to_many.html.erb +13 -0
  56. data/app/views/wallaby/resources/form/_has_many.html.erb +13 -0
  57. data/app/views/wallaby/resources/form/_has_one.html.erb +7 -0
  58. data/app/views/wallaby/resources/form/_hstore.html.erb +25 -0
  59. data/app/views/wallaby/resources/form/_inet.html.erb +9 -0
  60. data/app/views/wallaby/resources/form/_int4range.html.erb +18 -0
  61. data/app/views/wallaby/resources/form/_int8range.html.erb +18 -0
  62. data/app/views/wallaby/resources/form/_integer.html.erb +9 -0
  63. data/app/views/wallaby/resources/form/_json.html.erb +23 -0
  64. data/app/views/wallaby/resources/form/_jsonb.html.erb +23 -0
  65. data/app/views/wallaby/resources/form/_ltree.html.erb +5 -0
  66. data/app/views/wallaby/resources/form/_macaddr.html.erb +9 -0
  67. data/app/views/wallaby/resources/form/_money.html.erb +12 -0
  68. data/app/views/wallaby/resources/form/_numrange.html.erb +18 -0
  69. data/app/views/wallaby/resources/form/_password.html.erb +5 -0
  70. data/app/views/wallaby/resources/form/_point.html.erb +18 -0
  71. data/app/views/wallaby/resources/form/_string.html.erb +5 -0
  72. data/app/views/wallaby/resources/form/_text.html.erb +21 -0
  73. data/app/views/wallaby/resources/form/_time.html.erb +29 -0
  74. data/app/views/wallaby/resources/form/_tsrange.html.erb +38 -0
  75. data/app/views/wallaby/resources/form/_tstzrange.html.erb +38 -0
  76. data/app/views/wallaby/resources/form/_tsvector.html.erb +5 -0
  77. data/app/views/wallaby/resources/form/_uuid.html.erb +9 -0
  78. data/app/views/wallaby/resources/form/_xml.html.erb +23 -0
  79. data/app/views/wallaby/resources/index/_belongs_to.html.erb +1 -0
  80. data/app/views/wallaby/resources/index/_bigint.html.erb +1 -0
  81. data/app/views/wallaby/resources/index/_binary.html.erb +1 -0
  82. data/app/views/wallaby/resources/index/_bit.html.erb +5 -0
  83. data/app/views/wallaby/resources/index/_bit_varying.html.erb +5 -0
  84. data/app/views/wallaby/resources/index/_boolean.html.erb +5 -0
  85. data/app/views/wallaby/resources/index/_cidr.html.erb +6 -0
  86. data/app/views/wallaby/resources/index/_citext.html.erb +12 -0
  87. data/app/views/wallaby/resources/index/_color.html.erb +5 -0
  88. data/app/views/wallaby/resources/index/_date.html.erb +7 -0
  89. data/app/views/wallaby/resources/index/_daterange.html.erb +8 -0
  90. data/app/views/wallaby/resources/index/_datetime.html.erb +7 -0
  91. data/app/views/wallaby/resources/index/_decimal.html.erb +1 -0
  92. data/app/views/wallaby/resources/index/_email.html.erb +1 -0
  93. data/app/views/wallaby/resources/index/_float.html.erb +1 -0
  94. data/app/views/wallaby/resources/index/_has_and_belongs_to_many.html.erb +11 -0
  95. data/app/views/wallaby/resources/index/_has_many.html.erb +11 -0
  96. data/app/views/wallaby/resources/index/_has_one.html.erb +1 -0
  97. data/app/views/wallaby/resources/index/_hstore.html.erb +12 -0
  98. data/app/views/wallaby/resources/index/_inet.html.erb +6 -0
  99. data/app/views/wallaby/resources/index/_int4range.html.erb +7 -0
  100. data/app/views/wallaby/resources/index/_int8range.html.erb +7 -0
  101. data/app/views/wallaby/resources/index/_integer.html.erb +1 -0
  102. data/app/views/wallaby/resources/index/_json.html.erb +12 -0
  103. data/app/views/wallaby/resources/index/_jsonb.html.erb +12 -0
  104. data/app/views/wallaby/resources/index/_ltree.html.erb +12 -0
  105. data/app/views/wallaby/resources/index/_macaddr.html.erb +5 -0
  106. data/app/views/wallaby/resources/index/_money.html.erb +1 -0
  107. data/app/views/wallaby/resources/index/_numrange.html.erb +7 -0
  108. data/app/views/wallaby/resources/index/_point.html.erb +6 -0
  109. data/app/views/wallaby/resources/index/_string.html.erb +12 -0
  110. data/app/views/wallaby/resources/index/_text.html.erb +12 -0
  111. data/app/views/wallaby/resources/index/_time.html.erb +6 -0
  112. data/app/views/wallaby/resources/index/_tsrange.html.erb +8 -0
  113. data/app/views/wallaby/resources/index/_tstzrange.html.erb +8 -0
  114. data/app/views/wallaby/resources/index/_tsvector.html.erb +12 -0
  115. data/app/views/wallaby/resources/index/_uuid.html.erb +12 -0
  116. data/app/views/wallaby/resources/index/_xml.html.erb +12 -0
  117. data/app/views/wallaby/resources/index.html.erb +66 -0
  118. data/app/views/wallaby/resources/new.html.erb +14 -0
  119. data/app/views/wallaby/resources/shared/_resource_nav.html.erb +29 -0
  120. data/app/views/wallaby/resources/show/_belongs_to.html.erb +7 -0
  121. data/app/views/wallaby/resources/show/_bigint.html.erb +1 -0
  122. data/app/views/wallaby/resources/show/_binary.html.erb +1 -0
  123. data/app/views/wallaby/resources/show/_bit.html.erb +5 -0
  124. data/app/views/wallaby/resources/show/_bit_varying.html.erb +5 -0
  125. data/app/views/wallaby/resources/show/_boolean.html.erb +5 -0
  126. data/app/views/wallaby/resources/show/_cidr.html.erb +6 -0
  127. data/app/views/wallaby/resources/show/_citext.html.erb +1 -0
  128. data/app/views/wallaby/resources/show/_color.html.erb +5 -0
  129. data/app/views/wallaby/resources/show/_date.html.erb +7 -0
  130. data/app/views/wallaby/resources/show/_daterange.html.erb +7 -0
  131. data/app/views/wallaby/resources/show/_datetime.html.erb +6 -0
  132. data/app/views/wallaby/resources/show/_decimal.html.erb +1 -0
  133. data/app/views/wallaby/resources/show/_email.html.erb +1 -0
  134. data/app/views/wallaby/resources/show/_float.html.erb +1 -0
  135. data/app/views/wallaby/resources/show/_has_and_belongs_to_many.html.erb +5 -0
  136. data/app/views/wallaby/resources/show/_has_many.html.erb +5 -0
  137. data/app/views/wallaby/resources/show/_has_one.html.erb +1 -0
  138. data/app/views/wallaby/resources/show/_hstore.html.erb +5 -0
  139. data/app/views/wallaby/resources/show/_inet.html.erb +6 -0
  140. data/app/views/wallaby/resources/show/_int4range.html.erb +7 -0
  141. data/app/views/wallaby/resources/show/_int8range.html.erb +7 -0
  142. data/app/views/wallaby/resources/show/_integer.html.erb +1 -0
  143. data/app/views/wallaby/resources/show/_json.html.erb +5 -0
  144. data/app/views/wallaby/resources/show/_jsonb.html.erb +5 -0
  145. data/app/views/wallaby/resources/show/_ltree.html.erb +1 -0
  146. data/app/views/wallaby/resources/show/_macaddr.html.erb +5 -0
  147. data/app/views/wallaby/resources/show/_money.html.erb +1 -0
  148. data/app/views/wallaby/resources/show/_numrange.html.erb +7 -0
  149. data/app/views/wallaby/resources/show/_point.html.erb +6 -0
  150. data/app/views/wallaby/resources/show/_string.html.erb +1 -0
  151. data/app/views/wallaby/resources/show/_text.html.erb +1 -0
  152. data/app/views/wallaby/resources/show/_time.html.erb +6 -0
  153. data/app/views/wallaby/resources/show/_tsrange.html.erb +7 -0
  154. data/app/views/wallaby/resources/show/_tstzrange.html.erb +7 -0
  155. data/app/views/wallaby/resources/show/_tsvector.html.erb +1 -0
  156. data/app/views/wallaby/resources/show/_uuid.html.erb +5 -0
  157. data/app/views/wallaby/resources/show/_xml.html.erb +5 -0
  158. data/app/views/wallaby/resources/show.html.erb +31 -0
  159. data/app/views/wallaby/shared/_flash_messages.html.erb +13 -0
  160. data/config/locales/en.yml +29 -0
  161. data/config/routes.rb +34 -0
  162. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +105 -0
  163. data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +18 -0
  164. data/lib/adaptors/wallaby/active_record/model_decorator.rb +81 -0
  165. data/lib/adaptors/wallaby/active_record/model_finder.rb +12 -0
  166. data/lib/adaptors/wallaby/active_record/model_operator/normalizer.rb +44 -0
  167. data/lib/adaptors/wallaby/active_record/model_operator/permitter.rb +50 -0
  168. data/lib/adaptors/wallaby/active_record/model_operator/querier.rb +47 -0
  169. data/lib/adaptors/wallaby/active_record/model_operator/validator.rb +16 -0
  170. data/lib/adaptors/wallaby/active_record/model_operator.rb +82 -0
  171. data/lib/adaptors/wallaby/active_record.rb +2 -0
  172. data/lib/decorators/wallaby/resource_decorator.rb +78 -0
  173. data/lib/errors/wallaby/deprecated.rb +4 -0
  174. data/lib/errors/wallaby/general_error.rb +4 -0
  175. data/lib/errors/wallaby/invalid_error.rb +4 -0
  176. data/lib/errors/wallaby/model_not_found.rb +4 -0
  177. data/lib/errors/wallaby/not_authenticated.rb +4 -0
  178. data/lib/errors/wallaby/not_implemented.rb +4 -0
  179. data/lib/errors/wallaby/operation_not_found.rb +4 -0
  180. data/lib/errors/wallaby/resource_not_found.rb +4 -0
  181. data/lib/forms/wallaby/form_builder.rb +30 -0
  182. data/lib/handlers/wallaby/cached_compiled_erb.rb +14 -0
  183. data/lib/helpers/wallaby/application_helper.rb +30 -0
  184. data/lib/helpers/wallaby/core_helper.rb +50 -0
  185. data/lib/helpers/wallaby/form_helper.rb +21 -0
  186. data/lib/helpers/wallaby/links_helper.rb +83 -0
  187. data/lib/helpers/wallaby/paginatable_helper.rb +9 -0
  188. data/lib/helpers/wallaby/resources_helper.rb +55 -0
  189. data/lib/helpers/wallaby/secure_helper.rb +25 -0
  190. data/lib/helpers/wallaby/sorting_helper.rb +43 -0
  191. data/lib/helpers/wallaby/styling_helper.rb +57 -0
  192. data/lib/interfaces/wallaby/mode.rb +18 -0
  193. data/lib/interfaces/wallaby/model_decorator.rb +58 -0
  194. data/lib/interfaces/wallaby/model_finder.rb +5 -0
  195. data/lib/interfaces/wallaby/model_operator.rb +31 -0
  196. data/lib/services/wallaby/decorator_finder.rb +16 -0
  197. data/lib/services/wallaby/lookup_context_wrapper.rb +40 -0
  198. data/lib/services/wallaby/map.rb +53 -0
  199. data/lib/services/wallaby/model_servicer.rb +38 -0
  200. data/lib/services/wallaby/servicer_finder.rb +5 -0
  201. data/lib/tasks/wallaby_tasks.rake +4 -0
  202. data/lib/utils/wallaby/utils.rb +31 -0
  203. data/lib/wallaby/configuration/models.rb +17 -0
  204. data/lib/wallaby/configuration/security.rb +30 -0
  205. data/lib/wallaby/configuration.rb +49 -0
  206. data/lib/wallaby/engine.rb +89 -0
  207. data/lib/wallaby/version.rb +3 -0
  208. data/lib/wallaby.rb +5 -0
  209. 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('&times;'), 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,5 @@
1
+ class Wallaby::ModelFinder
2
+ def all
3
+ fail Wallaby::NotImplemented
4
+ end
5
+ 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,5 @@
1
+ class Wallaby::ServicerFinder
2
+ def self.find(model_class)
3
+ Wallaby::Map.servicer_map[model_class] || Wallaby::ModelServicer
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :wallaby do
3
+ # # Task goes here
4
+ # 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,17 @@
1
+ class Wallaby::Configuration::Models
2
+ def set(models)
3
+ @models = Array models
4
+ end
5
+
6
+ def presence
7
+ @models.presence
8
+ end
9
+
10
+ def excludes
11
+ @excludes ||= []
12
+ end
13
+
14
+ def exclude(*models)
15
+ @excludes = models
16
+ end
17
+ 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'