effective_developer 0.6.1 → 0.6.6
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|