dry_rails 0.5.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 45e9f1560278be794de82bb4b02b2810eaa2cf0754216b90449179fab98da9f1
4
+ data.tar.gz: 112c9c2b20d87a231e76213e910c3510404466d22fe527a0727ded5c32b77b6f
5
+ SHA512:
6
+ metadata.gz: 1d3a39eb7221fd5de5a04fae053a346007d2b0e4024e875ee5eff291587f232bdc43da69abfdc847b3c49fdfecfa32ae8cce359dc7ec78534e29ec5e21600ef8
7
+ data.tar.gz: 0cc139ffa109deeea728d3fd03b6313eafe6b485690e9a4a5e2132f561ef9f03ccc21a8df9040d67c97782ac4fff56aa76c0026fa8f3a188ddc54b2deedc5816
@@ -0,0 +1,32 @@
1
+ = form_for form_arguments(@record), html: { class: 'form' } do |f|
2
+ %fieldset
3
+ - if lookup_context.exists?('form_fieldset_before',
4
+ %W[#{@resource.model_name.route_key}/dry], true)
5
+ = render "#{@resource.model_name.route_key}/dry/form_fieldset_before"
6
+
7
+ - @resource.each_form_fields do |attr, type|
8
+ %p.field
9
+ - case type
10
+ - when Class
11
+ = f.label attr
12
+ %br
13
+ = f.collection_select attr, type.send(:all), :id, :to_s
14
+ - when Symbol
15
+ - if type == :check_box
16
+ = f.send type, attr
17
+ = f.label attr
18
+ - else
19
+ = f.label attr
20
+ %br
21
+ - form_control = ['form_field_for',
22
+ @resource.model_name.singular_route_key,
23
+ attr].join(?_).to_sym
24
+ - if respond_to? form_control
25
+ = send form_control, f
26
+ - else
27
+ = f.send type, attr
28
+
29
+ - if @record.errors.any?
30
+ = render "form_errors", record: @record
31
+
32
+ %p= f.button
@@ -0,0 +1,5 @@
1
+ .form-errors
2
+ %ul.errors-list
3
+ - @record.errors.full_messages.each do |error|
4
+ %li.error
5
+ = error
@@ -0,0 +1,15 @@
1
+ %h1
2
+ Editing
3
+ = @resource.singular_name
4
+
5
+
6
+ = render 'form'
7
+
8
+ %ul.actions
9
+ - if @resource.relations?
10
+ - @resource.relations.each do |relation|
11
+ - relation = @record.send(relation)
12
+ %li= link_to relation.model_name.human.pluralize,
13
+ relation_path(@record, relation)
14
+ %li
15
+ = link_to 'Back', collection_path(@resource)
@@ -0,0 +1,62 @@
1
+ %h1
2
+ Listing
3
+ = @resource.plural_name
4
+
5
+
6
+ - if @collection.empty?
7
+ %p
8
+ No
9
+ = @resource.singular_name
10
+ found.
11
+
12
+ - else
13
+ %table.list
14
+ %thead
15
+ %tr
16
+ %th
17
+ = @resource.singular_name.capitalize
18
+ - @resource.attrs_read.each do |attr|
19
+ %th= attr.capitalize
20
+ - if @resource.edit? || @resource.destroy?
21
+ %th.list-actions
22
+ Actions
23
+
24
+ %tbody
25
+ - @collection.each do |record|
26
+ %tr
27
+ %td
28
+ - if @resource.show?
29
+ = link_to record, record_path(record)
30
+ - else
31
+ = link_to record, edit_path(record)
32
+ - @resource.attrs_read.each do |attr|
33
+ %td
34
+ - attr_content = ['read_attr_content',
35
+ @resource.model_name.singular_route_key,
36
+ attr].join(?_).to_sym
37
+ - if respond_to? attr_content
38
+ = send attr_content, record
39
+ - else
40
+ = record.send attr
41
+ - if @resource.edit? || @resource.destroy?
42
+ %td.list-actions
43
+ %ul.actions
44
+ - if @resource.edit?
45
+ %li= link_to 'Edit', edit_path(record)
46
+ - if @resource.destroy?
47
+ %li= link_to 'Destroy', record_path(record), method: :delete,
48
+ data: { confirm: t('confirmation',
49
+ default: 'Are you sure?') }
50
+ - if @resource.relations?
51
+ - @resource.relations.each do |relation|
52
+ - relation = record.send(relation)
53
+ %li= link_to relation.model_name.human.pluralize,
54
+ relation_path(record, relation)
55
+
56
+
57
+ %ul.actions
58
+ - if @resource.new?
59
+ %li
60
+ = link_to "New #{@resource.singular_name}", new_path(@resource)
61
+ - if lookup_context.exists?('index_actions_extra', %w[dry], true)
62
+ = render 'dry/index_actions_extra'
@@ -0,0 +1,10 @@
1
+ %h1
2
+ New
3
+ = @resource.singular_name
4
+
5
+
6
+ = render 'form'
7
+
8
+ %ul.actions
9
+ %li
10
+ = link_to 'Back', collection_path(@resource)
@@ -0,0 +1,134 @@
1
+ module Dry
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+ include RoutingHelpers
5
+
6
+ included do
7
+ class_attribute :_dry_scope, instance_accessor: false
8
+
9
+ class_attribute :_dry_attrs, instance_accessor: false
10
+ self._dry_attrs = { read: [], write: [], options: {} }
11
+
12
+ class_attribute :_dry_nested_relations, instance_accessor: false
13
+ self._dry_nested_relations = []
14
+
15
+ append_view_path TemplateResolver.new
16
+
17
+ helper RoutingHelpers
18
+
19
+ before_filter :set_resource
20
+ before_filter :set_collection, only: :index
21
+ before_filter :set_record, only: %i[show edit update destroy]
22
+ end
23
+
24
+ module ClassMethods
25
+ def dry_scope &block
26
+ self._dry_scope = block
27
+ end
28
+
29
+ def dry_attrs_read *attrs
30
+ self._dry_attrs[:read] = attrs
31
+ end
32
+
33
+ def dry_attrs_write *attrs
34
+ self._dry_attrs[:write] = attrs
35
+ end
36
+
37
+ def dry_attrs_options **options
38
+ self._dry_attrs[:options] = options
39
+ end
40
+
41
+ def dry_nest *relations
42
+ self._dry_nested_relations.push *relations
43
+ end
44
+ end
45
+
46
+ def index
47
+ end
48
+
49
+ def show
50
+ end
51
+
52
+ def new
53
+ @record = resource_scope.new
54
+ end
55
+
56
+ def edit
57
+ end
58
+
59
+ def create
60
+ @record = resource_scope.new record_params
61
+ if @record.save
62
+ redirect_to collection_path(@resource),
63
+ notice: "#{model_name.singular.capitalize} was successfully created."
64
+ else
65
+ render :new
66
+ end
67
+ end
68
+
69
+ def update
70
+ if @record.update record_params
71
+ redirect_to collection_path(@resource),
72
+ notice: "#{model_name.singular.capitalize} was successfully updated."
73
+ else
74
+ render :edit
75
+ end
76
+ end
77
+
78
+ def destroy
79
+ @record.destroy
80
+ redirect_to collection_path(@resource),
81
+ notice: "#{model_name.singular.capitalize} was successfully destroyed."
82
+ end
83
+
84
+ private
85
+
86
+ def resource
87
+ @resource ||= Resource.new(controller_name.classify.constantize,
88
+ attrs_read: self.class._dry_attrs[:read],
89
+ attrs_write: self.class._dry_attrs[:write],
90
+ attrs_options: self.class._dry_attrs[:options],
91
+ relations: self.class._dry_nested_relations,
92
+ routes: resource_routes
93
+ )
94
+ end
95
+
96
+ def resource_routes
97
+ ResourceRoutes.new(Rails.application.routes.routes, controller_path)
98
+ .routes
99
+ end
100
+
101
+ def resource_scope
102
+ if b = self.class._dry_scope
103
+ instance_exec &b
104
+ else
105
+ resource.model
106
+ end
107
+ end
108
+
109
+ def model_name
110
+ resource.model_name
111
+ end
112
+
113
+ def collection
114
+ resource_scope.order 'created_at ASC'
115
+ end
116
+
117
+ def set_resource
118
+ resource
119
+ end
120
+
121
+ def set_collection
122
+ @collection = collection
123
+ end
124
+
125
+ def set_record
126
+ @record = resource_scope.find params[:id]
127
+ end
128
+
129
+ def record_params
130
+ params.require(model_name.param_key.to_sym)
131
+ .permit *self.class._dry_attrs[:write]
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,100 @@
1
+ module Dry
2
+ class Resource
3
+ DEFAULT_OPTIONS = {
4
+ attrs_read: [],
5
+ attrs_write: [],
6
+ attrs_options: {},
7
+ relations: [],
8
+ routes: []
9
+ }
10
+
11
+ ATTR_TYPE_TO_FORM_FIELD = {
12
+ boolean: :check_box,
13
+ decimal: :number_field,
14
+ integer: :number_field,
15
+ string: :text_field,
16
+ text: :text_area
17
+ }
18
+
19
+ ATTR_RELATION_PATTERN = /_id\z/.freeze
20
+
21
+ extend Forwardable
22
+ def_delegators :@model, :model_name
23
+
24
+ attr_reader :model
25
+
26
+ def initialize model, options = {}
27
+ @model = model
28
+ @options = DEFAULT_OPTIONS.merge options
29
+ end
30
+
31
+ def singular_name
32
+ model_name.singular
33
+ end
34
+
35
+ def plural_name
36
+ model_name.plural
37
+ end
38
+
39
+ def relations?
40
+ @options[:relations].any?
41
+ end
42
+
43
+ def relations
44
+ @options[:relations]
45
+ end
46
+
47
+ def show?
48
+ has_route_for? :show
49
+ end
50
+
51
+ def new?
52
+ has_route_for? :new
53
+ end
54
+
55
+ def edit?
56
+ has_route_for? :edit
57
+ end
58
+
59
+ def destroy?
60
+ has_route_for? :destroy
61
+ end
62
+
63
+ def attrs_read
64
+ @options[:attrs_read]
65
+ end
66
+
67
+ def attrs_write
68
+ @options[:attrs_write]
69
+ end
70
+
71
+ def attrs_options
72
+ @options[:attrs_options]
73
+ end
74
+
75
+ def each_form_fields
76
+ attrs_write.each do |e|
77
+ if e =~ ATTR_RELATION_PATTERN
78
+ yield e,
79
+ @model.reflections[e.to_s.sub ATTR_RELATION_PATTERN, ''].klass
80
+ else
81
+ yield e, form_field_for(e)
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def has_route_for? action
89
+ @options[:routes].include? action
90
+ end
91
+
92
+ def form_field_for attr
93
+ if type = attrs_options[attr]
94
+ type
95
+ else
96
+ ATTR_TYPE_TO_FORM_FIELD[@model.column_types[attr.to_s].type]
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,20 @@
1
+ module Dry
2
+ class ResourceRoutes
3
+ def initialize routes, path
4
+ @routes = routes
5
+ @path = path
6
+ end
7
+
8
+ def routes
9
+ routes_for_path(@path).each_with_object([]) do |e, m|
10
+ m << e.defaults[:action].to_sym
11
+ end.uniq
12
+ end
13
+
14
+ private
15
+
16
+ def routes_for_path path
17
+ @routes.select { |e| e.defaults[:controller] == @path }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ module Dry
2
+ module RoutingHelpers
3
+ def collection_path resource
4
+ send "#{base_path resource, plural: true}_path"
5
+ end
6
+
7
+ def record_path record
8
+ send "#{base_path record.class}_path", *([@parent, record].compact)
9
+ end
10
+
11
+ def new_path resource
12
+ send "new_#{base_path resource}_path"
13
+ end
14
+
15
+ def edit_path record
16
+ send "edit_#{base_path record.class}_path", *([@parent, record].compact)
17
+ end
18
+
19
+ def relation_path record, relation
20
+ send "#{base_path record.class}_#{relation.model_name.route_key}_path",
21
+ record
22
+ end
23
+
24
+ def form_arguments record
25
+ [*current_namespace, @parent, record].compact
26
+ end
27
+
28
+ private
29
+
30
+ def current_namespace
31
+ (controller_path.split('/') - [controller_name]).map &:to_sym
32
+ end
33
+
34
+ def base_path klass, plural: false
35
+ path = [*current_namespace].flatten
36
+ path << parent_class.model_name.singular_route_key if parent?
37
+ path << klass.model_name.send(plural ? :route_key : :singular_route_key)
38
+ path * '_'
39
+ end
40
+
41
+ def parent?
42
+ !!@parent
43
+ end
44
+
45
+ def parent_class
46
+ @parent ? @parent.class : nil
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,11 @@
1
+ require 'action_view/template/resolver.rb'
2
+
3
+ module Dry
4
+ class TemplateResolver < ::ActionView::FileSystemResolver
5
+ DRY_PATTERN = DEFAULT_PATTERN.sub /:prefix\//, ''
6
+
7
+ def initialize
8
+ super Dry.view_path, DRY_PATTERN
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Dry
2
+ VERSION = '0.5.0'.freeze
3
+ end
data/lib/dry.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'forwardable'
2
+
3
+ module Dry
4
+ class << self
5
+ def view_path
6
+ File.expand_path('../../app/views', __FILE__)
7
+ end
8
+
9
+ def lib_path
10
+ File.expand_path('..', __FILE__)
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dry_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Thibault Jouan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: haml
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: capybara
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ - - "<"
105
+ - !ruby/object:Gem::Version
106
+ version: '1.4'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '1.3'
114
+ - - "<"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.4'
117
+ description:
118
+ email: tj@a13.fr
119
+ executables: []
120
+ extensions: []
121
+ extra_rdoc_files: []
122
+ files:
123
+ - app/views/_form.haml
124
+ - app/views/_form_errors.haml
125
+ - app/views/edit.haml
126
+ - app/views/index.haml
127
+ - app/views/new.haml
128
+ - lib/dry.rb
129
+ - lib/dry/controller.rb
130
+ - lib/dry/resource.rb
131
+ - lib/dry/resource_routes.rb
132
+ - lib/dry/routing_helpers.rb
133
+ - lib/dry/template_resolver.rb
134
+ - lib/dry/version.rb
135
+ homepage:
136
+ licenses:
137
+ - BSD-3-Clause
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubygems_version: 3.0.3
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: Dry
158
+ test_files: []