effective_developer 0.6.1 → 0.6.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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/app/jobs/effective/asset_replacer_job.rb +17 -0
- data/app/models/effective/annotator.rb +81 -0
- data/app/models/effective/asset_replacer.rb +156 -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/app/models/effective/snippet_replacer.rb +66 -0
- data/lib/effective_developer/engine.rb +3 -0
- data/lib/effective_developer/version.rb +1 -1
- data/lib/tasks/annotate.rake +8 -0
- data/lib/tasks/pg_pull.rake +1 -1
- data/lib/tasks/replace_effective_assets.rake +5 -0
- data/lib/tasks/replace_effective_snippets.rake +5 -0
- data/lib/tasks/upgrade_forms.rake +7 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3a6071b2027da0c4eb454ff1d2446f014c557a99cb495190c5594d2d9ecda81
|
4
|
+
data.tar.gz: 3bdec7afda572520e2ac59ba94ca47116ea4019a2b582cc71e6c4bd0e28e0467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c013f0c196b01b41860abe74341736f2a5bffbc45781a5190c38e68cb642145c5de1784b3473183a83e1b72fc97991be459f169f7d72165f37961c406a17115
|
7
|
+
data.tar.gz: 27a7d4470f8c02d76826e220861d9f43fa6cbe715059363a3fa010721878541586f6d831281114226806075adcb00bc994bb96deb1a1fdca49e0fe3addfbc365
|
data/MIT-LICENSE
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Effective
|
2
|
+
class AssetReplacerJob < ::ApplicationJob
|
3
|
+
|
4
|
+
queue_as :default
|
5
|
+
|
6
|
+
if defined?(Sidekiq)
|
7
|
+
# The retry setting works. But none of these waits seem to. Still getting exponential backoff.
|
8
|
+
sidekiq_options retry: 2, retry_in: 10, wait: 10
|
9
|
+
sidekiq_retry_in { |count, exception| 10 }
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(attachment, box)
|
13
|
+
Effective::AssetReplacer.new.replace_attachment!(attachment, box)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -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
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Looks at the Effective::Asset and Effective::Attachments and converts to ActiveStorage
|
2
|
+
#
|
3
|
+
# 1. Put in the has_attached_files to each model to be upgraded
|
4
|
+
# 2. Remove the acts_as_asset_box
|
5
|
+
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
module Effective
|
9
|
+
class AssetReplacer
|
10
|
+
include ActiveStorage::Blob::Analyzable
|
11
|
+
|
12
|
+
BATCH_SIZE = 500
|
13
|
+
TIMEOUT = 120
|
14
|
+
|
15
|
+
def replace!(skip_existing: false)
|
16
|
+
verify!
|
17
|
+
|
18
|
+
attachments = attachments_to_process().to_a
|
19
|
+
|
20
|
+
while(true)
|
21
|
+
wait_for_active_job!
|
22
|
+
|
23
|
+
puts "\nEnqueuing #{attachments.length} attachments with ids #{attachments.first.id} to #{attachments.last.id}"
|
24
|
+
|
25
|
+
attachments.each do |attachment|
|
26
|
+
asset = attachment.asset
|
27
|
+
attachable = attachment.attachable
|
28
|
+
next if asset.blank? || attachable.blank?
|
29
|
+
|
30
|
+
box = attachment.box.singularize
|
31
|
+
boxes = attachment.box
|
32
|
+
|
33
|
+
one = attachable.respond_to?(box) && attachable.send(box).kind_of?(ActiveStorage::Attached::One)
|
34
|
+
many = attachable.respond_to?(boxes) && attachable.send(boxes).kind_of?(ActiveStorage::Attached::Many)
|
35
|
+
box = (one ? box : boxes)
|
36
|
+
|
37
|
+
if skip_existing
|
38
|
+
existing = Array(attachable.send(box))
|
39
|
+
|
40
|
+
if existing.any? { |obj| obj.respond_to?(:filename) && obj.filename.to_s == asset.file_name }
|
41
|
+
puts("Skipping existing #{attachable.class.name} #{attachable.id} #{box} #{asset.file_name}.")
|
42
|
+
next
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Effective::AssetReplacerJob.perform_later(attachment, box)
|
47
|
+
end
|
48
|
+
|
49
|
+
attachments = attachments_to_process().where.not(id: attachments.map(&:id))
|
50
|
+
break if attachments.to_a.blank?
|
51
|
+
|
52
|
+
GC.start
|
53
|
+
end
|
54
|
+
|
55
|
+
puts "\nAll Done. Have a great day."
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
# This is called on the background by the AssetReplacerJob
|
60
|
+
def replace_attachment!(attachment, box)
|
61
|
+
raise('expected an Effective::Attachment') unless attachment.kind_of?(Effective::Attachment)
|
62
|
+
puts("Processing attachment ##{attachment.id}")
|
63
|
+
|
64
|
+
asset = attachment.asset
|
65
|
+
attachable = attachment.attachable
|
66
|
+
|
67
|
+
attachable.replacing_asset = true if attachable.respond_to?(:replacing_asset=)
|
68
|
+
|
69
|
+
Timeout.timeout(TIMEOUT) do
|
70
|
+
attachable.send(box).attach(
|
71
|
+
io: URI.open(asset.url),
|
72
|
+
filename: asset.file_name,
|
73
|
+
content_type: asset.content_type.presence,
|
74
|
+
identify: (asset.content_type.blank?)
|
75
|
+
)
|
76
|
+
|
77
|
+
attachment.update_column(:replaced, true)
|
78
|
+
end
|
79
|
+
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def verify!
|
84
|
+
raise('expected effective assets') unless defined?(Effective::Asset)
|
85
|
+
raise('expected active storage') unless defined?(ActiveStorage)
|
86
|
+
|
87
|
+
unless Effective::Attachment.new.respond_to?(:replaced?)
|
88
|
+
raise('please add a replaced boolean to Effective::Attachment. add_column :attachments, :replaced, :boolean')
|
89
|
+
end
|
90
|
+
|
91
|
+
(Effective::Attachment.all.pluck(:attachable_type, :box).uniq).each do |name, boxes|
|
92
|
+
next if name.blank? || boxes.blank?
|
93
|
+
|
94
|
+
box = boxes.singularize
|
95
|
+
|
96
|
+
klass = name.safe_constantize
|
97
|
+
raise("invalid class #{klass}") unless klass.present?
|
98
|
+
|
99
|
+
instance = klass.new
|
100
|
+
|
101
|
+
if instance.respond_to?(:effective_assets)
|
102
|
+
raise("please remove acts_as_asset_box() from #{klass.name}")
|
103
|
+
end
|
104
|
+
|
105
|
+
unless instance.respond_to?(box) || instance.respond_to?(boxes)
|
106
|
+
raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
|
107
|
+
end
|
108
|
+
|
109
|
+
one = instance.respond_to?(box) && instance.send(box).kind_of?(ActiveStorage::Attached::One)
|
110
|
+
many = instance.respond_to?(boxes) && instance.send(boxes).kind_of?(ActiveStorage::Attached::Many)
|
111
|
+
|
112
|
+
unless one.present? || many.present?
|
113
|
+
raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
puts 'All attachment classes verified.'
|
118
|
+
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
def reset!
|
123
|
+
Effective::Attachment.update_all(replaced: false)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def wait_for_active_job!
|
129
|
+
while(true)
|
130
|
+
if(jobs = enqueued_jobs_count) > (BATCH_SIZE / 10)
|
131
|
+
print '.'; sleep(3)
|
132
|
+
else
|
133
|
+
break
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# The last BATCH_SIZE attachments
|
139
|
+
def attachments_to_process
|
140
|
+
Effective::Attachment.all
|
141
|
+
.includes(:asset)
|
142
|
+
.where(replaced: [nil, false])
|
143
|
+
.reorder(id: :desc)
|
144
|
+
.limit(BATCH_SIZE)
|
145
|
+
end
|
146
|
+
|
147
|
+
def enqueued_jobs_count
|
148
|
+
if Rails.application.config.active_job.queue_adapter == :sidekiq
|
149
|
+
Sidekiq::Stats.new.enqueued.to_i
|
150
|
+
else
|
151
|
+
ActiveJob::Base.queue_adapter.enqueued_jobs.count
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
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
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Replaces the [snippet_x] in all effective regions with static content
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class SnippetReplacer
|
5
|
+
include ActiveStorage::Blob::Analyzable
|
6
|
+
include ActionView::Helpers::UrlHelper
|
7
|
+
include ActionView::Helpers::AssetTagHelper
|
8
|
+
|
9
|
+
def replace!
|
10
|
+
raise('expected effective regions') unless defined?(Effective::Region)
|
11
|
+
raise('expected effective assets') unless defined?(Effective::Asset)
|
12
|
+
raise('expected active storage') unless defined?(ActiveStorage)
|
13
|
+
|
14
|
+
Effective::Region.with_snippets.find_each do |region|
|
15
|
+
region.snippet_objects.each do |snippet|
|
16
|
+
print('.')
|
17
|
+
|
18
|
+
begin
|
19
|
+
case snippet.class.name
|
20
|
+
when 'Effective::Snippets::EffectiveAsset'
|
21
|
+
replace_effective_asset(region, snippet)
|
22
|
+
else
|
23
|
+
raise("unsupported snippet: #{snippet.class.name}")
|
24
|
+
end
|
25
|
+
rescue => e
|
26
|
+
puts "\nError: #{e}\n"
|
27
|
+
remove_snippet(region, snippet)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
region.save!
|
32
|
+
end
|
33
|
+
|
34
|
+
puts 'All Done. Have a great day.'
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def replace_effective_asset(region, snippet)
|
41
|
+
asset = snippet.asset
|
42
|
+
raise("Effective:Asset id=#{snippet.asset_id || 'none'} does not exist") unless asset.present?
|
43
|
+
|
44
|
+
blob = ActiveStorage::Blob.create_and_upload!(io: URI.open(asset.url), filename: asset.file_name)
|
45
|
+
url = Rails.application.routes.url_helpers.rails_blob_url(blob, only_path: true)
|
46
|
+
|
47
|
+
content = if asset.image?
|
48
|
+
image_tag(url, class: snippet.html_class, alt: snippet.link_title)
|
49
|
+
else
|
50
|
+
link_to(snippet.link_title, url, class: snippet.html_class, title: snippet.link_title)
|
51
|
+
end
|
52
|
+
|
53
|
+
region.content.sub!("[#{snippet.id}]", content.to_s)
|
54
|
+
region.snippets.delete(snippet.id)
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_snippet(region, snippet)
|
60
|
+
region.content.sub!("[#{snippet.id}]", '')
|
61
|
+
region.snippets.delete(snippet.id)
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -2,6 +2,9 @@ module EffectiveDeveloper
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
engine_name 'effective_developer'
|
4
4
|
|
5
|
+
config.autoload_paths += Dir["#{config.root}/models/jobs/"]
|
6
|
+
config.eager_load_paths += Dir["#{config.root}/models/jobs/"]
|
7
|
+
|
5
8
|
# Set up our default configuration options.
|
6
9
|
initializer 'effective_developer.defaults', before: :load_config_initializers do |app|
|
7
10
|
# Set up our defaults, as per our initializer template
|
@@ -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
@@ -50,7 +50,7 @@ namespace :pg do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
# Hatchbox mode
|
53
|
-
if (ENV['HATCHBOX_IP'] || args[:remote]).count('.') == 3
|
53
|
+
if (ENV['HATCHBOX_IP'] || args[:remote]).to_s.count('.') == 3
|
54
54
|
args.with_defaults(
|
55
55
|
remote: ENV.fetch('HATCHBOX_IP'),
|
56
56
|
app: ENV['HATCHBOX_APP'] || `pwd`.split('/').last.chomp,
|
@@ -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.6.
|
4
|
+
version: 0.6.6
|
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-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -48,10 +48,15 @@ files:
|
|
48
48
|
- MIT-LICENSE
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
|
+
- app/jobs/effective/asset_replacer_job.rb
|
52
|
+
- app/models/effective/annotator.rb
|
53
|
+
- app/models/effective/asset_replacer.rb
|
51
54
|
- app/models/effective/code_writer.rb
|
52
55
|
- app/models/effective/csv_importer.rb
|
56
|
+
- app/models/effective/form_upgrader.rb
|
53
57
|
- app/models/effective/live_generator.rb
|
54
58
|
- app/models/effective/profiler.rb
|
59
|
+
- app/models/effective/snippet_replacer.rb
|
55
60
|
- config/effective_developer.rb
|
56
61
|
- lib/effective_developer.rb
|
57
62
|
- lib/effective_developer/engine.rb
|
@@ -95,10 +100,14 @@ files:
|
|
95
100
|
- lib/scaffolds/importers/csv_importer.rb
|
96
101
|
- lib/scaffolds/models/model.rb
|
97
102
|
- lib/scaffolds/views/_resource.html.haml
|
103
|
+
- lib/tasks/annotate.rake
|
98
104
|
- lib/tasks/effective_csv_importer.rake
|
99
105
|
- lib/tasks/pg_pull.rake
|
100
106
|
- lib/tasks/rename_class.rake
|
107
|
+
- lib/tasks/replace_effective_assets.rake
|
108
|
+
- lib/tasks/replace_effective_snippets.rake
|
101
109
|
- lib/tasks/reset_pk_sequence.rake
|
110
|
+
- lib/tasks/upgrade_forms.rake
|
102
111
|
- lib/tasks/validate.rake
|
103
112
|
homepage: https://github.com/code-and-effect/effective_developer
|
104
113
|
licenses:
|