effective_developer 0.5.5 → 0.6.4
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/app/models/effective/annotator.rb +81 -0
- data/app/models/effective/code_writer.rb +8 -2
- data/app/models/effective/form_upgrader.rb +197 -0
- data/app/models/effective/profiler.rb +0 -2
- data/lib/effective_developer/version.rb +1 -1
- data/lib/generators/effective/ability_generator.rb +17 -5
- data/lib/generators/effective/controller_generator.rb +4 -0
- data/lib/generators/effective/datatable_generator.rb +9 -2
- data/lib/generators/effective/form_generator.rb +13 -5
- data/lib/generators/effective/helpers.rb +33 -13
- data/lib/generators/effective/menu_generator.rb +8 -3
- data/lib/generators/effective/migration_generator.rb +33 -7
- data/lib/generators/effective/route_generator.rb +6 -2
- data/lib/generators/effective/views_generator.rb +4 -0
- data/lib/scaffolds/controllers/controller.rb +9 -1
- data/lib/scaffolds/datatables/datatable.rb +37 -2
- data/lib/scaffolds/forms/tabbed/_form.html.haml +1 -1
- data/lib/scaffolds/forms/tabbed/_form_resource.html.haml +5 -1
- data/lib/tasks/annotate.rake +8 -0
- data/lib/tasks/pg_pull.rake +31 -22
- data/lib/tasks/upgrade_forms.rake +7 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d495b7c0e191545d03edac8297a4e6d70b0e73c60e3e750a7746a43a9c45ae0
|
4
|
+
data.tar.gz: fda29335818a87f2e76bd21c4f8018aab29833082682ca931339a127d7a9d1d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bbed134e5bc6f0b78231501cd866a581a878dd4b5734ca74b480bfc49bc014c25a5e2a23074a62ccdc4ac90d40220ed6a7f5fb42a8c68c44979fd909d427635
|
7
|
+
data.tar.gz: b97abb74e30855a39100c9ca66785e89148bfda8e1cc427170b67767007078a5818e194adf34541806d6c4809a3b45bf1bfba97305bff663c4643c21c319d347
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Writes the effective_resource do .. end block into the model file
|
2
|
+
module Effective
|
3
|
+
class Annotator
|
4
|
+
|
5
|
+
def initialize(resource: 'All', folders: 'app/models/')
|
6
|
+
@resources = Array(resource).map { |resource| resource.to_s.classify }
|
7
|
+
@folders = Array(folders)
|
8
|
+
end
|
9
|
+
|
10
|
+
def annotate!
|
11
|
+
@folders.each do |folder|
|
12
|
+
Dir.glob(folder + '**/*').each do |path|
|
13
|
+
next if File.directory?(path)
|
14
|
+
|
15
|
+
name = path.sub(folder, '').split('.')[0...-1].join('.')
|
16
|
+
resource = Effective::Resource.new(name)
|
17
|
+
klass = resource.klass
|
18
|
+
|
19
|
+
next if klass.blank?
|
20
|
+
next unless klass.ancestors.include?(ActiveRecord::Base)
|
21
|
+
next if klass.abstract_class?
|
22
|
+
next unless @resources.include?('All') || @resources.include?(klass.name)
|
23
|
+
|
24
|
+
annotate(resource, path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
puts 'All Done. Have a great day.'
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def annotate(resource, path)
|
35
|
+
puts "Annotate: #{path}"
|
36
|
+
|
37
|
+
Effective::CodeWriter.new(path) do |writer|
|
38
|
+
index = find_insert_at(writer)
|
39
|
+
content = build_content(resource)
|
40
|
+
|
41
|
+
remove_existing(writer)
|
42
|
+
writer.insert(content, index)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_insert_at(writer)
|
47
|
+
index = writer.first { |line| line.include?('effective_resource do') || line.include?('structure do') }
|
48
|
+
|
49
|
+
index ||= begin
|
50
|
+
index = writer.first { |line| line.include?('validates :') || line.include?('scope :') || line.include?('def ') }
|
51
|
+
index - 1 if index
|
52
|
+
end
|
53
|
+
|
54
|
+
[1, index.to_i-1].max
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_existing(writer)
|
58
|
+
from = writer.first { |line| line.include?('effective_resource do') || line.include?('structure do') }
|
59
|
+
return unless from.present?
|
60
|
+
|
61
|
+
to = writer.first(from: from) { |line| line == 'end' || line == '# end' }
|
62
|
+
return unless to.present?
|
63
|
+
|
64
|
+
writer.remove(from: from, to: to+1)
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_content(resource)
|
68
|
+
attributes = resource.klass_attributes(all: true)
|
69
|
+
atts = attributes.except(resource.klass.primary_key.to_sym, :created_at, :updated_at)
|
70
|
+
|
71
|
+
max = atts.map { |k, v| k.to_s.length }.max.to_i + 4
|
72
|
+
max = max + 1 unless (max % 2 == 0)
|
73
|
+
|
74
|
+
lines = atts.map { |k, v| k.to_s + (' ' * (max - k.to_s.length)) + ":#{v.first}" }
|
75
|
+
lines += ['', 'timestamps'] if attributes.key?(:created_at) && attributes.key?(:updated_at)
|
76
|
+
|
77
|
+
['effective_resource do'] + lines + ['end']
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -228,13 +228,17 @@ module Effective
|
|
228
228
|
lines.each { |line| @changed = true if line.gsub!(source, target) }
|
229
229
|
end
|
230
230
|
|
231
|
+
def remove(from:, to:)
|
232
|
+
raise('expected from to be less than to') unless from.present? && to.present? && (from < to)
|
233
|
+
@changed = true
|
234
|
+
(to - from).times { lines.delete_at(from) }
|
235
|
+
end
|
236
|
+
|
231
237
|
def replace(index, content)
|
232
238
|
@changed = true
|
233
239
|
lines[index].replace(content.to_s)
|
234
240
|
end
|
235
241
|
|
236
|
-
private
|
237
|
-
|
238
242
|
def write!
|
239
243
|
return false unless changed?
|
240
244
|
|
@@ -245,6 +249,8 @@ module Effective
|
|
245
249
|
true
|
246
250
|
end
|
247
251
|
|
252
|
+
private
|
253
|
+
|
248
254
|
def open?(content)
|
249
255
|
stripped = ss(content)
|
250
256
|
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# Upgrades simple_form_for to effective_form_with
|
2
|
+
module Effective
|
3
|
+
class FormUpgrader
|
4
|
+
|
5
|
+
def initialize(folder: 'app/views/')
|
6
|
+
@folders = Array(folder)
|
7
|
+
end
|
8
|
+
|
9
|
+
def upgrade!
|
10
|
+
@folders.each do |folder|
|
11
|
+
Dir.glob(folder + '**/*').each do |path|
|
12
|
+
next if File.directory?(path)
|
13
|
+
next unless path.include?('.html')
|
14
|
+
|
15
|
+
writer = Effective::CodeWriter.new(path)
|
16
|
+
|
17
|
+
name = path.split('/')[0...-1] - ['app', 'views']
|
18
|
+
resource = Effective::Resource.new(name)
|
19
|
+
|
20
|
+
if writer.find { |line| line.include?('simple_form_for') }
|
21
|
+
upgrade_simple_form(writer, resource)
|
22
|
+
elsif writer.find { |line| line.include?('semantic_form_for') }
|
23
|
+
upgrade_formtastic(writer, resource)
|
24
|
+
elsif writer.find { |line| line.include?('form_for') }
|
25
|
+
upgrade_form_for(writer, resource)
|
26
|
+
else
|
27
|
+
next # Nothing to do
|
28
|
+
end
|
29
|
+
|
30
|
+
writer.write!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
puts 'All Done. Have a great day.'
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
SIMPLE_FORM_FOR_REGEX = /simple_form_for( |\()(\[:[^,]+, ?[^,]+\])?(([^,]+),)?.+do \|(\w+)\|/
|
41
|
+
SIMPLE_FORM_INPUT_ATTRIBUTE = /\.input( |\():(\w+)/
|
42
|
+
SIMPLE_FORM_INPUT_AS_ONE = /(as: :(\w+))/
|
43
|
+
SIMPLE_FORM_INPUT_AS_TWO = /(:as => :(\w+))/
|
44
|
+
SIMPLE_FORM_INPUT_COLLECTION_ONE = /(collection: ([^,]+?))(,|$)/
|
45
|
+
SIMPLE_FORM_INPUT_COLLECTION_TWO = /(:collection => :([^,]+?))(,|$)/
|
46
|
+
|
47
|
+
def upgrade_simple_form(writer, resource)
|
48
|
+
puts "Upgrading simple form: #{writer.filename}"
|
49
|
+
|
50
|
+
letter = nil
|
51
|
+
model = nil
|
52
|
+
|
53
|
+
# Replace simple_form_for
|
54
|
+
writer.all { |line| line.include?('simple_form_for') }.each do |line|
|
55
|
+
content = writer.lines[line]
|
56
|
+
matched = content.match(SIMPLE_FORM_FOR_REGEX)
|
57
|
+
raise("unable to match simple_form_for from:\n#{content}") unless matched.present?
|
58
|
+
|
59
|
+
original = matched[0]
|
60
|
+
model = matched[2] || matched[4]
|
61
|
+
letter = matched[5]
|
62
|
+
|
63
|
+
raise("unable to determine simple_form_for subject from:\n#{content}") unless original && model && letter
|
64
|
+
|
65
|
+
content.sub!(original, "effective_form_with(model: #{model}) do |#{letter}|")
|
66
|
+
writer.replace(line, content)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Try to figure out klass again if its missing from filename
|
70
|
+
if resource.klass.blank? && model.present?
|
71
|
+
name = model.sub('[', '').sub(']', '').sub(' ', '').split(',').map do |value|
|
72
|
+
value.sub('current_', '').sub('@', '').sub(':', '')
|
73
|
+
end
|
74
|
+
|
75
|
+
resource = Effective::Resource.new(name)
|
76
|
+
end
|
77
|
+
|
78
|
+
if resource.klass.blank? && writer.filename.include?('/devise/')
|
79
|
+
resource = Effective::Resource.new('user')
|
80
|
+
end
|
81
|
+
|
82
|
+
if resource.klass.blank?
|
83
|
+
puts " => Warning: Unable to determine klass of #{model}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Replace .input
|
87
|
+
writer.all { |line| line.include?('.input :') }.each do |line|
|
88
|
+
content = writer.lines[line]
|
89
|
+
attribute = content.match(SIMPLE_FORM_INPUT_ATTRIBUTE)
|
90
|
+
raise("unable to match simple_form_for input attribute from\n#{content}") unless attribute.present?
|
91
|
+
|
92
|
+
as = content.match(SIMPLE_FORM_INPUT_AS_ONE) || content.match(SIMPLE_FORM_INPUT_AS_TWO)
|
93
|
+
collection = content.match(SIMPLE_FORM_INPUT_COLLECTION_ONE) || content.match(SIMPLE_FORM_INPUT_COLLECTION_TWO)
|
94
|
+
|
95
|
+
if as.present?
|
96
|
+
content.sub!(",#{as[0]}", '')
|
97
|
+
content.sub!(", #{as[0]}", '')
|
98
|
+
end
|
99
|
+
|
100
|
+
if collection.present?
|
101
|
+
content.sub!(",#{collection[0]}", ',')
|
102
|
+
content.sub!(", #{collection[0]}", ',')
|
103
|
+
content.sub!(attribute[0], "#{attribute[0]} #{collection[2]},")
|
104
|
+
end
|
105
|
+
|
106
|
+
input_type = find_input_type(resource: resource, attribute: attribute[2], as: (as[2] if as))
|
107
|
+
|
108
|
+
content.sub!('input', input_type)
|
109
|
+
writer.replace(line, content)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Replace simple_fields_for
|
113
|
+
writer.all { |line| line.include?(".simple_fields_for") }.each do |line|
|
114
|
+
content = writer.lines[line]
|
115
|
+
|
116
|
+
content.sub!(".simple_fields_for", ".has_many")
|
117
|
+
writer.replace(line, content)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Replace f.submit
|
121
|
+
writer.all { |line| line.include?("#{letter}.submit") }.each do |line|
|
122
|
+
content = writer.lines[line]
|
123
|
+
|
124
|
+
content.sub!("#{letter}.submit", "#{letter}.save")
|
125
|
+
writer.replace(line, content)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Replace f.button :submit
|
129
|
+
writer.all { |line| line.include?(".button :submit,") }.each do |line|
|
130
|
+
content = writer.lines[line]
|
131
|
+
|
132
|
+
content.sub!(".button :submit,", ".submit")
|
133
|
+
writer.replace(line, content)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Replace .form-actions
|
137
|
+
writer.all { |line| line == '.form-actions' }.each do |line|
|
138
|
+
content = writer.lines[line]
|
139
|
+
|
140
|
+
content.sub!('.form-actions', "= #{letter}.submit do")
|
141
|
+
writer.replace(line, content)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def upgrade_formtastic(writer, resource)
|
146
|
+
puts "Detected formtastic: #{writer.filename}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def upgrade_form_for(writer, resource)
|
150
|
+
puts "Detected rails form_for: #{writer.filename}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def find_input_type(attribute:, resource:, as: nil)
|
154
|
+
input_type = (as || resource.sql_type(attribute)).to_s
|
155
|
+
|
156
|
+
case input_type
|
157
|
+
when 'asset_box_simple_form' then 'file_field'
|
158
|
+
when 'belongs_to', 'belongs_to_polymorphic' then 'select'
|
159
|
+
when 'boolean' then 'check_box'
|
160
|
+
when 'check_boxes' then 'checks'
|
161
|
+
when 'date' then 'date_field'
|
162
|
+
when 'datetime' then 'datetime_field'
|
163
|
+
when 'decimal' then 'float_field'
|
164
|
+
when 'effective_ckeditor_text_area' then 'rich_text_area' # I guess
|
165
|
+
when 'effective_date_picker' then 'date_field'
|
166
|
+
when 'effective_date_time_picker' then 'datetime_field'
|
167
|
+
when 'effective_email' then 'email_field'
|
168
|
+
when 'effective_price' then 'price_field'
|
169
|
+
when 'effective_radio_buttons' then 'radios'
|
170
|
+
when 'effective_select' then 'select'
|
171
|
+
when 'effective_static_control' then 'static_field'
|
172
|
+
when 'effective_tel' then 'phone_field'
|
173
|
+
when 'effective_time_picker' then 'time_field'
|
174
|
+
when 'effective_url' then 'url_field'
|
175
|
+
when 'email' then 'email_field'
|
176
|
+
when 'file' then 'file_field'
|
177
|
+
when 'hidden' then 'hidden_field'
|
178
|
+
when 'integer' then 'number_field'
|
179
|
+
when 'number' then 'number_field'
|
180
|
+
when 'password' then 'password_field'
|
181
|
+
when 'phone' then 'phone_field'
|
182
|
+
when 'price' then 'price_field'
|
183
|
+
when 'radio_buttons' then 'radios'
|
184
|
+
when 'search' then 'search_field'
|
185
|
+
when 'select' then 'select'
|
186
|
+
when 'static_control' then 'static_field'
|
187
|
+
when 'string' then 'text_field'
|
188
|
+
when 'tel', 'telephone' then 'phone_field'
|
189
|
+
when 'text' then 'text_area'
|
190
|
+
when 'url' then 'url_field'
|
191
|
+
else
|
192
|
+
raise("unknown input type #{input_type} (for attribute :#{attribute})")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
@@ -15,20 +15,26 @@ module Effective
|
|
15
15
|
|
16
16
|
argument :actions, type: :array, default: ['crud'], banner: 'action action'
|
17
17
|
|
18
|
+
def validate_resource
|
19
|
+
exit unless resource_valid?
|
20
|
+
end
|
21
|
+
|
18
22
|
def invoke_ability
|
19
23
|
say_status :invoke, :ability, :white
|
20
24
|
end
|
21
25
|
|
22
26
|
def create_ability
|
23
|
-
unless File.exists?(
|
27
|
+
unless File.exists?(resource.abilities_file)
|
24
28
|
say_status(:skipped, :ability, :yellow) and return
|
25
29
|
end
|
26
30
|
|
27
|
-
Effective::CodeWriter.new(
|
28
|
-
if w.find { |line, depth| depth == 2 && line == ability }
|
31
|
+
Effective::CodeWriter.new(resource.abilities_file) do |w|
|
32
|
+
if w.find { |line, depth| (depth == 2 || depth == 3) && line == ability }
|
29
33
|
say_status :identical, ability, :blue
|
30
34
|
else
|
31
|
-
w.insert_into_first(ability) { |line, depth| line.start_with?('def initialize') }
|
35
|
+
w.insert_into_first(ability + "\n") { |line, depth| line.start_with?('def initialize') || line.end_with?('abilities(user)') }
|
36
|
+
|
37
|
+
say_status :ability, ability
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
@@ -55,7 +61,13 @@ module Effective
|
|
55
61
|
abilities = '[' + abilities.map { |action| ':' + action }.join(', ') + ']'
|
56
62
|
end
|
57
63
|
|
58
|
-
|
64
|
+
name = if resource.module_name.present?
|
65
|
+
resource.class_name.split('::').last
|
66
|
+
else
|
67
|
+
resource.class_name
|
68
|
+
end
|
69
|
+
|
70
|
+
"can #{abilities}, #{name}"
|
59
71
|
)
|
60
72
|
end
|
61
73
|
end
|
@@ -17,6 +17,10 @@ module Effective
|
|
17
17
|
argument :actions, type: :array, default: ['crud'], banner: 'action action'
|
18
18
|
class_option :attributes, type: :array, default: [], desc: 'Included permitted params, otherwise read from model'
|
19
19
|
|
20
|
+
def validate_resource
|
21
|
+
exit unless resource_valid?
|
22
|
+
end
|
23
|
+
|
20
24
|
def assign_actions
|
21
25
|
@actions = invoked_actions
|
22
26
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# Generates a datatable
|
6
6
|
# rails generate effective:datatable Thing
|
7
|
-
# rails generate effective:
|
7
|
+
# rails generate effective:datatable Thing name:string description:text
|
8
8
|
|
9
9
|
module Effective
|
10
10
|
module Generators
|
@@ -18,6 +18,10 @@ module Effective
|
|
18
18
|
argument :actions, type: :array, default: ['crud'], banner: 'action action'
|
19
19
|
class_option :attributes, type: :array, default: [], desc: 'Included permitted params, otherwise read from model'
|
20
20
|
|
21
|
+
def validate_resource
|
22
|
+
exit unless resource_valid?
|
23
|
+
end
|
24
|
+
|
21
25
|
def assign_attributes
|
22
26
|
@attributes = invoked_attributes.presence || resource_attributes(all: true)
|
23
27
|
self.class.send(:attr_reader, :attributes)
|
@@ -32,7 +36,10 @@ module Effective
|
|
32
36
|
say_status(:skipped, :datatable, :yellow) and return
|
33
37
|
end
|
34
38
|
|
35
|
-
|
39
|
+
with_resource_tenant do
|
40
|
+
template 'datatables/datatable.rb', resource.datatable_file
|
41
|
+
end
|
42
|
+
|
36
43
|
end
|
37
44
|
|
38
45
|
end
|
@@ -20,6 +20,10 @@ module Effective
|
|
20
20
|
argument :attributes, type: :array, default: [], banner: 'field[:type] field[:type]'
|
21
21
|
class_option :tabbed, type: :string, default: 'true'
|
22
22
|
|
23
|
+
def validate_resource
|
24
|
+
exit unless resource_valid?
|
25
|
+
end
|
26
|
+
|
23
27
|
def assign_attributes
|
24
28
|
@attributes = invoked_attributes.presence || resource_attributes
|
25
29
|
self.class.send(:attr_reader, :attributes)
|
@@ -30,15 +34,19 @@ module Effective
|
|
30
34
|
end
|
31
35
|
|
32
36
|
def create_flat_form
|
33
|
-
|
34
|
-
|
37
|
+
with_resource_tenant do
|
38
|
+
if options[:tabbed] == 'false'
|
39
|
+
template 'forms/flat/_form.html.haml', resource.view_file('form', partial: true)
|
40
|
+
end
|
35
41
|
end
|
36
42
|
end
|
37
43
|
|
38
44
|
def create_tabbed_form
|
39
|
-
|
40
|
-
|
41
|
-
|
45
|
+
with_resource_tenant do
|
46
|
+
if options[:tabbed] == 'true'
|
47
|
+
template 'forms/tabbed/_form.html.haml', resource.view_file('form', partial: true)
|
48
|
+
template 'forms/tabbed/_form_resource.html.haml', resource.view_file("form_#{resource.name}", partial: true)
|
49
|
+
end
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
@@ -4,6 +4,24 @@ module Effective
|
|
4
4
|
|
5
5
|
protected
|
6
6
|
|
7
|
+
# This is kind of a validate for the resource
|
8
|
+
def resource_valid?
|
9
|
+
if resource.klass.blank?
|
10
|
+
say_status(:error, "Unable to find resource klass from #{name}", :red)
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_resource_tenant(&block)
|
18
|
+
if defined?(Tenant) && resource.tenant.present?
|
19
|
+
Tenant.as(resource.tenant) { yield }
|
20
|
+
else
|
21
|
+
yield
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
7
25
|
def resource
|
8
26
|
@resource ||= Effective::Resource.new(name)
|
9
27
|
end
|
@@ -55,24 +73,26 @@ module Effective
|
|
55
73
|
end
|
56
74
|
|
57
75
|
def resource_attributes(all: false)
|
58
|
-
|
76
|
+
with_resource_tenant do
|
77
|
+
klass_attributes = resource.klass_attributes(all: all)
|
59
78
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
79
|
+
if klass_attributes.blank?
|
80
|
+
if ActiveRecord::Migration.respond_to?(:check_pending!)
|
81
|
+
pending = (ActiveRecord::Migration.check_pending! rescue true)
|
82
|
+
else
|
83
|
+
pending = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths)).pending_migrations.present?
|
84
|
+
end
|
66
85
|
|
67
|
-
|
68
|
-
|
69
|
-
|
86
|
+
if pending
|
87
|
+
migrate = ask("Unable to read the attributes of #{resource.klass || resource.name}. There are pending migrations. Run db:migrate now? [y/n]")
|
88
|
+
system('bundle exec rake db:migrate') if migrate.to_s.include?('y')
|
89
|
+
end
|
90
|
+
|
91
|
+
klass_attributes = resource.klass_attributes(all: all)
|
70
92
|
end
|
71
93
|
|
72
|
-
klass_attributes
|
94
|
+
klass_attributes.presence || resource.model_attributes(all: all)
|
73
95
|
end
|
74
|
-
|
75
|
-
klass_attributes.presence || resource.model_attributes(all: all)
|
76
96
|
end
|
77
97
|
|
78
98
|
end
|
@@ -13,6 +13,10 @@ module Effective
|
|
13
13
|
|
14
14
|
desc 'Adds a menu link to an existing _navbar.html.haml'
|
15
15
|
|
16
|
+
def validate_resource
|
17
|
+
exit unless resource_valid?
|
18
|
+
end
|
19
|
+
|
16
20
|
def invoke_menu
|
17
21
|
say_status :invoke, :menu, :white
|
18
22
|
end
|
@@ -22,7 +26,7 @@ module Effective
|
|
22
26
|
return unless resource.namespaces.blank?
|
23
27
|
|
24
28
|
begin
|
25
|
-
Effective::CodeWriter.new(
|
29
|
+
Effective::CodeWriter.new(resource.menu_file) do |w|
|
26
30
|
if w.find { |line, _| line == menu_content.second.strip }
|
27
31
|
say_status :identical, menu_path, :blue
|
28
32
|
else
|
@@ -44,7 +48,7 @@ module Effective
|
|
44
48
|
return unless resource.namespaces == ['admin']
|
45
49
|
|
46
50
|
begin
|
47
|
-
Effective::CodeWriter.new(
|
51
|
+
Effective::CodeWriter.new(resource.admin_menu_file) do |w|
|
48
52
|
if w.find { |line, _| line == menu_content.second.strip }
|
49
53
|
say_status :identical, menu_path, :blue
|
50
54
|
else
|
@@ -72,7 +76,8 @@ module Effective
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def menu_path
|
75
|
-
[resource.namespace, resource.plural_name, 'path'].compact * '_'
|
79
|
+
path = [resource.namespace, resource.plural_name, 'path'].compact * '_'
|
80
|
+
resource.tenant.present? ? "#{resource.tenant}.#{path}" : path
|
76
81
|
end
|
77
82
|
end
|
78
83
|
end
|
@@ -16,21 +16,47 @@ module Effective
|
|
16
16
|
desc 'Creates a migration.'
|
17
17
|
|
18
18
|
argument :attributes, type: :array, default: [], banner: 'field[:type] field[:type]'
|
19
|
+
class_option :database, type: :string, desc: "Database to generate the migration for"
|
20
|
+
|
21
|
+
def validate_resource
|
22
|
+
exit unless resource_valid?
|
23
|
+
end
|
19
24
|
|
20
25
|
def invoke_migration
|
21
26
|
say_status :invoke, :migration, :white
|
22
27
|
end
|
23
28
|
|
29
|
+
# rails generate effective:migration courses body:text --database example
|
24
30
|
def create_migration
|
25
31
|
if invoked_attributes.present?
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
args = ["create_#{plural_name}"] + (invokable(invoked_attributes) | timestamps)
|
33
|
+
args += ["--database", options['database']] if options['database']
|
34
|
+
Rails::Generators.invoke('migration', args)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
return if with_resource_tenant do
|
39
|
+
table_name = resource.klass.table_name
|
40
|
+
|
41
|
+
if ActiveRecord::Base.connection.table_exists?(table_name)
|
42
|
+
say_status(:error, "#{table_name} table already exist. We can't migrate (yet). Exiting.", :red)
|
43
|
+
true
|
44
|
+
end
|
33
45
|
end
|
46
|
+
|
47
|
+
if resource.model_attributes.blank?
|
48
|
+
say_status(:error, "No model attributes present. Please add the effective_resource do ... end block and try again", :red)
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
args = ["create_#{plural_name}"] + invokable(resource.model_attributes) - timestamps
|
53
|
+
args += ["--database", options['database']] if options['database']
|
54
|
+
|
55
|
+
if options['database'].blank? && defined?(Tenant)
|
56
|
+
args += ["--database", resource.klass.name.split('::').first.downcase]
|
57
|
+
end
|
58
|
+
|
59
|
+
Rails::Generators.invoke('migration', args)
|
34
60
|
end
|
35
61
|
|
36
62
|
protected
|
@@ -15,6 +15,10 @@ module Effective
|
|
15
15
|
|
16
16
|
argument :actions, type: :array, default: ['crud'], banner: 'action action'
|
17
17
|
|
18
|
+
def validate_resource
|
19
|
+
exit unless resource_valid?
|
20
|
+
end
|
21
|
+
|
18
22
|
def invoke_route
|
19
23
|
say_status :invoke, :route, :white
|
20
24
|
end
|
@@ -22,7 +26,7 @@ module Effective
|
|
22
26
|
def create_route
|
23
27
|
blocks = []
|
24
28
|
|
25
|
-
Effective::CodeWriter.new(
|
29
|
+
Effective::CodeWriter.new(resource.routes_file) do |w|
|
26
30
|
resource.namespaces.each do |namespace|
|
27
31
|
index = nil
|
28
32
|
|
@@ -54,7 +58,7 @@ module Effective
|
|
54
58
|
|
55
59
|
def resources
|
56
60
|
@resources ||= (
|
57
|
-
resources = "resources :#{plural_name}"
|
61
|
+
resources = "resources :#{resource.plural_name}"
|
58
62
|
|
59
63
|
if ((crud_actions - ['show']) == invoked_actions)
|
60
64
|
resources << ', except: [:show]'
|
@@ -16,6 +16,10 @@ module Effective
|
|
16
16
|
argument :actions, type: :array, default: ['crud'], banner: 'action action'
|
17
17
|
class_option :attributes, type: :array, default: [], desc: 'Included form attributes, otherwise read from model'
|
18
18
|
|
19
|
+
def validate_resource
|
20
|
+
exit unless resource_valid?
|
21
|
+
end
|
22
|
+
|
19
23
|
def assign_attributes
|
20
24
|
@attributes = (invoked_attributes.presence || resource_attributes).except(:archived)
|
21
25
|
self.class.send(:attr_reader, :attributes)
|
@@ -1,3 +1,11 @@
|
|
1
|
-
|
1
|
+
<% if resource.module_name.present? -%>
|
2
|
+
module <%= resource.module_name %>
|
3
|
+
class <%= resource.module_namespaced %>Controller < <%= resource.module_namespace %>ApplicationController
|
4
|
+
include Effective::CrudController
|
5
|
+
end
|
6
|
+
end
|
7
|
+
<% else -%>
|
8
|
+
class <%= resource.namespaced_class_name.pluralize %>Controller < <%= resource.module_namespace %>ApplicationController
|
2
9
|
include Effective::CrudController
|
3
10
|
end
|
11
|
+
<% end -%>
|
@@ -1,5 +1,40 @@
|
|
1
|
-
|
1
|
+
<% if resource.module_name.present? -%>
|
2
|
+
module <%= resource.module_name %>
|
3
|
+
class <%= resource.module_namespaced %>Datatable < Effective::Datatable
|
4
|
+
datatable do
|
5
|
+
order :updated_at
|
6
|
+
|
7
|
+
col :updated_at, visible: false
|
8
|
+
col :created_at, visible: false
|
9
|
+
col :id, visible: false
|
2
10
|
|
11
|
+
<% if resource.belong_tos.present? || resource.has_anys.present? -%>
|
12
|
+
<% resource.belong_tos.each do |reference| -%>
|
13
|
+
col :<%= reference.name %>
|
14
|
+
<% end -%>
|
15
|
+
<% resource.has_anys.each do |reference| -%>
|
16
|
+
col :<%= reference.name %>
|
17
|
+
<% end -%>
|
18
|
+
|
19
|
+
<% end -%>
|
20
|
+
<% attributes.except(:created_at, :updated_at, :id, :archived).each do |name, _| -%>
|
21
|
+
col :<%= name %>
|
22
|
+
<% end -%>
|
23
|
+
<% if attributes.key?(:archived) -%>
|
24
|
+
|
25
|
+
col :archived, search: { value: false }
|
26
|
+
<% end -%>
|
27
|
+
|
28
|
+
actions_col
|
29
|
+
end
|
30
|
+
|
31
|
+
collection do
|
32
|
+
<%= resource.class_name %>.deep.all
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
<% else -%>
|
37
|
+
class <%= resource.namespaced_class_name.pluralize %>Datatable < Effective::Datatable
|
3
38
|
datatable do
|
4
39
|
order :updated_at
|
5
40
|
|
@@ -30,5 +65,5 @@ class <%= resource.namespaced_class_name.pluralize %>Datatable < Effective::Data
|
|
30
65
|
collection do
|
31
66
|
<%= resource.class_name %>.deep.all
|
32
67
|
end
|
33
|
-
|
34
68
|
end
|
69
|
+
<% end -%>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
= tabs do
|
2
2
|
= tab '<%= resource.human_name.titleize %>' do
|
3
|
-
= render '
|
3
|
+
= render '<%= resource.view_file_path("form_#{resource.name}") %>', <%= resource.name %>: <%= resource.name %>
|
4
4
|
|
5
5
|
<%- if resource.nested_resources.present? || resource.instance.respond_to?(:log_changes_datatable) %>
|
6
6
|
- if <%= resource.name %>.persisted?
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
<% if resource.namespace.present? -%>
|
2
|
+
= effective_form_with(model: [:<%= resource.namespace %>, <%= resource.name %>]) do |f|
|
3
|
+
<% else -%>
|
4
|
+
= effective_form_with(model: <%= resource.name %>) do |f|
|
5
|
+
<% end -%>
|
2
6
|
<% resource.belong_tos.each do |reference| -%>
|
3
7
|
<%= render_field(reference, depth: 1) %>
|
4
8
|
<% end -%>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# bundle exec rake annotate
|
2
|
+
# bundle exec rake annotate[user]
|
3
|
+
|
4
|
+
desc 'Adds an effective_resources do .. end block to all ActiveRecord model files'
|
5
|
+
task :annotate, [:resource] => :environment do |t, args|
|
6
|
+
args.with_defaults(resource: 'all')
|
7
|
+
Effective::Annotator.new(resource: args.resource).annotate!
|
8
|
+
end
|
data/lib/tasks/pg_pull.rake
CHANGED
@@ -4,14 +4,35 @@ namespace :pg do
|
|
4
4
|
# bundle exec rake pg:pull
|
5
5
|
# bundle exec rake pg:pull[staging]
|
6
6
|
# bundle exec rake pg:pull[158.204.33.124]
|
7
|
+
|
8
|
+
# bundle exec rake pg:pull
|
9
|
+
# bundle exec rake pg:pull[staging]
|
10
|
+
# bundle exec rake pg:pull[158.204.33.124]
|
11
|
+
# bundle exec rake pg:pull filename=latest.dump database=example
|
12
|
+
# DATABASE=example bundle exec rake pg:load
|
7
13
|
desc 'Creates a new backup on remote server and downloads it to latest.dump'
|
8
14
|
task :pull, [:remote] => :environment do |t, args|
|
15
|
+
defaults = { database: nil, filename: (ENV['DATABASE'] || 'latest') + '.dump' }
|
16
|
+
env_keys = { database: ENV['DATABASE'], filename: ENV['FILENAME'] }
|
17
|
+
keywords = ARGV.map { |a| a.split('=') if a.include?('=') }.compact.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
18
|
+
args.with_defaults(defaults.compact.merge(env_keys.compact).merge(keywords))
|
19
|
+
|
20
|
+
# Validate Config
|
21
|
+
config = ActiveRecord::Base.configurations[Rails.env]
|
22
|
+
configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
|
23
|
+
|
24
|
+
if configs.length > 1 && args.database.blank?
|
25
|
+
puts "Multiple database configs exist for #{Rails.env} environment."
|
26
|
+
puts "Please run bundle exec rake pg:pull database=x"
|
27
|
+
puts "Where x is one of: #{configs.map { |config| config.name }.to_sentence}"
|
28
|
+
exit
|
29
|
+
end
|
9
30
|
|
10
31
|
# Heroku mode
|
11
32
|
if `git remote -v | grep heroku`.length > 0
|
12
33
|
args.with_defaults(remote: 'heroku')
|
13
34
|
|
14
|
-
puts "=== Pulling remote '#{args.remote}' database into
|
35
|
+
puts "=== Pulling remote '#{args.remote}' #{args.database} database into #{args.filename}"
|
15
36
|
|
16
37
|
# Create a backup on heroku
|
17
38
|
unless system("heroku pg:backups:capture --remote #{args.remote}")
|
@@ -19,41 +40,41 @@ namespace :pg do
|
|
19
40
|
end
|
20
41
|
|
21
42
|
# Download it to local
|
22
|
-
unless system("curl -o
|
43
|
+
unless system("curl -o #{args.filename} `heroku pg:backups:public-url --remote #{args.remote}`")
|
23
44
|
abort("Error downloading database")
|
24
45
|
end
|
25
46
|
|
26
47
|
# Load it
|
27
|
-
Rake::Task['pg:load'].invoke
|
48
|
+
Rake::Task['pg:load'].invoke(*args)
|
28
49
|
exit
|
29
50
|
end
|
30
51
|
|
31
52
|
# Hatchbox mode
|
32
|
-
if (ENV['HATCHBOX_IP'] || args[:remote]).count('.') == 3
|
53
|
+
if (ENV['HATCHBOX_IP'] || args[:remote]).to_s.count('.') == 3
|
33
54
|
args.with_defaults(
|
34
55
|
remote: ENV.fetch('HATCHBOX_IP'),
|
35
56
|
app: ENV['HATCHBOX_APP'] || `pwd`.split('/').last.chomp,
|
36
57
|
user: ENV['HATCHBOX_USER'] || 'deploy'
|
37
58
|
)
|
38
59
|
|
39
|
-
puts "=== Pulling hatchbox '#{args.remote}' #{args.app} database into
|
60
|
+
puts "=== Pulling hatchbox '#{args.remote}' #{args.app} #{args.database} database into #{args.filename}"
|
40
61
|
|
41
62
|
# SSH into hatchbox and call rake pg:save there to create latest.dump
|
42
|
-
unless(result = `ssh #{args.user}@#{args.remote} << EOF
|
63
|
+
unless(result = `ssh -T #{args.user}@#{args.remote} << EOF
|
43
64
|
cd ~/#{args.app}/current/
|
44
|
-
bundle exec rake pg:save
|
65
|
+
bundle exec rake pg:save database=#{args.database} filename=#{args.filename}
|
45
66
|
`).include?('Saving database completed') # The output of pg:save down below
|
46
67
|
puts("Error calling ssh #{args.user}@#{args.remote} and running rake pg:save on hatchbox from ~/#{args.app}/current/")
|
47
68
|
abort(result)
|
48
69
|
end
|
49
70
|
|
50
71
|
# SCP to copy the hatchkbox latest.dump to local
|
51
|
-
unless system("scp #{args.user}@#{args.remote}:~/#{args.app}/current
|
72
|
+
unless system("scp #{args.user}@#{args.remote}:~/#{args.app}/current/#{args.filename} ./")
|
52
73
|
abort("Error downloading database")
|
53
74
|
end
|
54
75
|
|
55
76
|
# Load it
|
56
|
-
Rake::Task['pg:load'].invoke
|
77
|
+
Rake::Task['pg:load'].invoke(*args)
|
57
78
|
exit
|
58
79
|
end
|
59
80
|
|
@@ -67,6 +88,7 @@ namespace :pg do
|
|
67
88
|
# bundle exec rake pg:load => Will replace the current database with latest.dump
|
68
89
|
# bundle exec rake pg:load[something.dump] => Will replace the current database with something.dump
|
69
90
|
# bundle exec rake pg:load filename=latest.dump database=example
|
91
|
+
# DATABASE=example bundle exec rake pg:load
|
70
92
|
desc 'Loads a postgresql .dump file into the development database (latest.dump by default)'
|
71
93
|
task :load, [:filename] => :environment do |t, args|
|
72
94
|
defaults = { database: nil, filename: (ENV['DATABASE'] || 'latest') + '.dump' }
|
@@ -106,19 +128,6 @@ namespace :pg do
|
|
106
128
|
|
107
129
|
puts "=== Loading #{args.filename} into local '#{db[:database]}' database"
|
108
130
|
|
109
|
-
# bin/rails db:environment:set RAILS_ENV=development
|
110
|
-
if Rails.env != 'production'
|
111
|
-
ENV['DISABLE_DATABASE_ENVIRONMENT_CHECK'] = '1'
|
112
|
-
end
|
113
|
-
|
114
|
-
if configs.length > 1
|
115
|
-
Rake::Task["db:drop:#{args.database}"].invoke
|
116
|
-
Rake::Task["db:create:#{args.database}"].invoke
|
117
|
-
else
|
118
|
-
Rake::Task['db:drop'].invoke
|
119
|
-
Rake::Task['db:create'].invoke
|
120
|
-
end
|
121
|
-
|
122
131
|
if system("export PGPASSWORD=#{db[:password]}; pg_restore --no-acl --no-owner --clean --if-exists -h #{db[:host]} -U #{db[:username]} -d #{db[:database]} #{args.filename}")
|
123
132
|
puts "Loading database completed"
|
124
133
|
else
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# bundle exec rake upgrade_forms
|
2
|
+
# bundle exec rake upgrade_forms[app/views/admin/]
|
3
|
+
desc 'Upgrades simple_form_for to effective_form_with'
|
4
|
+
task :upgrade_forms, [:folder] => :environment do |t, args|
|
5
|
+
args.with_defaults(folder: 'app/views/')
|
6
|
+
Effective::FormUpgrader.new(folder: args.folder).upgrade!
|
7
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_developer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -48,8 +48,10 @@ files:
|
|
48
48
|
- MIT-LICENSE
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
|
+
- app/models/effective/annotator.rb
|
51
52
|
- app/models/effective/code_writer.rb
|
52
53
|
- app/models/effective/csv_importer.rb
|
54
|
+
- app/models/effective/form_upgrader.rb
|
53
55
|
- app/models/effective/live_generator.rb
|
54
56
|
- app/models/effective/profiler.rb
|
55
57
|
- config/effective_developer.rb
|
@@ -95,10 +97,12 @@ files:
|
|
95
97
|
- lib/scaffolds/importers/csv_importer.rb
|
96
98
|
- lib/scaffolds/models/model.rb
|
97
99
|
- lib/scaffolds/views/_resource.html.haml
|
100
|
+
- lib/tasks/annotate.rake
|
98
101
|
- lib/tasks/effective_csv_importer.rake
|
99
102
|
- lib/tasks/pg_pull.rake
|
100
103
|
- lib/tasks/rename_class.rake
|
101
104
|
- lib/tasks/reset_pk_sequence.rake
|
105
|
+
- lib/tasks/upgrade_forms.rake
|
102
106
|
- lib/tasks/validate.rake
|
103
107
|
homepage: https://github.com/code-and-effect/effective_developer
|
104
108
|
licenses:
|