peak_flow_utils 0.0.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/{LICENSE.txt → MIT-LICENSE} +1 -1
- data/README.md +22 -13
- data/Rakefile +20 -30
- data/app/assets/config/peak_flow_utils_manifest.js +2 -0
- data/app/assets/javascripts/peak_flow_utils/application.js +14 -0
- data/app/assets/stylesheets/peak_flow_utils/application.css +15 -0
- data/app/controllers/peak_flow_utils/application_controller.rb +13 -0
- data/app/controllers/peak_flow_utils/pings/sidekiq_pings_controller.rb +10 -0
- data/app/handlers/peak_flow_utils/application_handler.rb +36 -0
- data/app/handlers/peak_flow_utils/devise_handler.rb +126 -0
- data/app/handlers/peak_flow_utils/file_handler.rb +42 -0
- data/app/handlers/peak_flow_utils/model_handler.rb +123 -0
- data/app/handlers/peak_flow_utils/rails_handler.rb +206 -0
- data/app/handlers/peak_flow_utils/simple_form_handler.rb +76 -0
- data/app/handlers/peak_flow_utils/validations_handler.rb +85 -0
- data/app/handlers/peak_flow_utils/will_paginate_handler.rb +59 -0
- data/app/helpers/peak_flow_utils/application_helper.rb +2 -0
- data/app/jobs/peak_flow_utils/application_job.rb +2 -0
- data/app/mailers/peak_flow_utils/application_mailer.rb +4 -0
- data/app/migrations/20150902155200_create_translation_keys.rb +8 -0
- data/app/migrations/20150907070909_create_groups.rb +12 -0
- data/app/migrations/20150907090900_create_handlers.rb +9 -0
- data/app/migrations/20150908085500_create_translation_values.rb +13 -0
- data/app/migrations/20150908090800_create_handler_texts.rb +22 -0
- data/app/migrations/20160411190500_create_scanned_files.rb +10 -0
- data/app/migrations/peak_flow_utils/application_migration.rb +5 -0
- data/app/models/peak_flow_utils/application_record.rb +9 -0
- data/app/models/peak_flow_utils/group.rb +22 -0
- data/app/models/peak_flow_utils/handler.rb +14 -0
- data/app/models/peak_flow_utils/handler_text.rb +46 -0
- data/app/models/peak_flow_utils/scanned_file.rb +2 -0
- data/app/models/peak_flow_utils/translation_key.rb +8 -0
- data/app/models/peak_flow_utils/translation_value.rb +24 -0
- data/app/services/peak_flow_utils/application_service.rb +2 -0
- data/app/services/peak_flow_utils/attribute_service.rb +32 -0
- data/app/services/peak_flow_utils/configuration_service.rb +11 -0
- data/app/services/peak_flow_utils/database_initializer_service.rb +39 -0
- data/app/services/peak_flow_utils/erb_inspector.rb +71 -0
- data/app/services/peak_flow_utils/erb_inspector/file_inspector.rb +137 -0
- data/app/services/peak_flow_utils/erb_inspector/translation_inspector.rb +100 -0
- data/app/services/peak_flow_utils/group_service.rb +50 -0
- data/app/services/peak_flow_utils/handlers_finder_service.rb +25 -0
- data/app/services/peak_flow_utils/model_inspector.rb +133 -0
- data/app/services/peak_flow_utils/translation_service.rb +138 -0
- data/app/services/peak_flow_utils/translations_parser_service.rb +211 -0
- data/app/views/layouts/peak_flow_utils/application.html.erb +14 -0
- data/bin/peak_flow_rspec_files +4 -2
- data/config/routes.rb +2 -0
- data/lib/peak_flow_utils.rb +10 -2
- data/lib/peak_flow_utils/engine.rb +7 -0
- data/lib/peak_flow_utils/handler_helper.rb +39 -0
- data/lib/peak_flow_utils/rspec_helper.rb +162 -25
- data/lib/peak_flow_utils/version.rb +3 -0
- data/lib/tasks/peak_flow_utils_tasks.rake +6 -0
- metadata +121 -42
- data/.document +0 -5
- data/.rspec +0 -1
- data/.rubocop.yml +0 -83
- data/Gemfile +0 -20
- data/Gemfile.lock +0 -93
- data/VERSION +0 -1
- data/peak_flow_utils.gemspec +0 -65
- data/spec/peak_flow_utils_spec.rb +0 -7
- data/spec/spec_helper.rb +0 -12
@@ -0,0 +1,100 @@
|
|
1
|
+
class PeakFlowUtils::ErbInspector::TranslationInspector
|
2
|
+
attr_reader :dir, :file_path, :last_method, :line_no, :method, :key, :full_key, :full_path, :root_path
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@file_path = args[:file_path]
|
6
|
+
@full_path = args[:full_path]
|
7
|
+
@line_no = args[:line_no]
|
8
|
+
@method = args[:method]
|
9
|
+
@key = args[:key]
|
10
|
+
@root_path = args[:root_path]
|
11
|
+
@last_method = args[:last_method]
|
12
|
+
|
13
|
+
@full_path = "#{@root_path}/#{@file_path}"
|
14
|
+
|
15
|
+
generate_full_key
|
16
|
+
generate_dir
|
17
|
+
end
|
18
|
+
|
19
|
+
def model
|
20
|
+
PeakFlowUtils::TranslationService.new(
|
21
|
+
key: @full_key,
|
22
|
+
dir: @dir,
|
23
|
+
full_path: @full_path,
|
24
|
+
file_path: @file_path,
|
25
|
+
line_no: @line_no
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def global?
|
30
|
+
!relative? && !key.include?(".")
|
31
|
+
end
|
32
|
+
|
33
|
+
def relative?
|
34
|
+
key.start_with?(".")
|
35
|
+
end
|
36
|
+
|
37
|
+
def contains_interpolations?
|
38
|
+
key =~ /#\{(.+?)\}/
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def generate_full_key
|
44
|
+
if (@method == "t" || @method == "helper_t" || @method == "controller_t" || @method == "I18n-js.t") && @key.start_with?(".")
|
45
|
+
@full_key = File.dirname(@file_path).to_s
|
46
|
+
|
47
|
+
if @full_key.starts_with?("app/mailers")
|
48
|
+
@full_key.gsub!(/\Aapp\/mailers(\/|)/, "")
|
49
|
+
is_mailer = true
|
50
|
+
elsif @full_key.start_with?("app/views/")
|
51
|
+
# Remove "app/views" from view-translations since that doesn't get used in keys.
|
52
|
+
@full_key.gsub!(/\Aapp\/views\//, "")
|
53
|
+
elsif @full_key.start_with?("app/controllers")
|
54
|
+
# Remove "app/controllers" from controller-translations since that doesn't get used in keys.
|
55
|
+
@full_key.gsub!(/\Aapp\/controllers(\/?)/, "")
|
56
|
+
is_controller = true
|
57
|
+
elsif @full_key.start_with?("app/cells")
|
58
|
+
@full_key.gsub!(/\Aapp\/cells\//, "")
|
59
|
+
elsif @full_key.start_with?("app/")
|
60
|
+
# Remove "app" from controller- and helper-translations since that doesn't get used.
|
61
|
+
@full_key.gsub!(/\Aapp\//, "")
|
62
|
+
end
|
63
|
+
|
64
|
+
@full_key.tr!("/", ".")
|
65
|
+
@full_key << "." unless @full_key.empty?
|
66
|
+
@full_key << file_key(@file_path)
|
67
|
+
@full_key << ".#{@last_method}" if (is_mailer || is_controller) && @last_method && @method != "controller_t"
|
68
|
+
@full_key << "."
|
69
|
+
@full_key << @key.gsub(/\A\./, "")
|
70
|
+
elsif @method == "I18n-js.t" || @method == "t" || @method == "helper_t" || @method == "controller_t"
|
71
|
+
@full_key = @key
|
72
|
+
else
|
73
|
+
raise "Unknown method-name: '#{@method}'."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def file_key(file_path)
|
78
|
+
key = File.basename(file_path)
|
79
|
+
|
80
|
+
# Remove extension
|
81
|
+
key = key.match(/\A(.+?)\./)[1]
|
82
|
+
|
83
|
+
# Remove leading "_" from partials
|
84
|
+
key = key.gsub(/\A_/, "")
|
85
|
+
|
86
|
+
# Remove '_controller' from controllers
|
87
|
+
key = key.gsub(/_controller\Z/, "")
|
88
|
+
|
89
|
+
key
|
90
|
+
end
|
91
|
+
|
92
|
+
def generate_dir
|
93
|
+
parts = %w[config locales awesome_translations]
|
94
|
+
|
95
|
+
key_parts = @full_key.split(".").reject(&:blank?)
|
96
|
+
key_parts.pop
|
97
|
+
|
98
|
+
@dir = Rails.root.join(*(parts + key_parts)).to_s
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class PeakFlowUtils::GroupService
|
2
|
+
attr_reader :handler, :id, :data
|
3
|
+
|
4
|
+
def self.find_by_handler_and_id(handler, id)
|
5
|
+
handler.groups.each do |group|
|
6
|
+
return group if group.id == id.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
raise ActiveRecord::RecordNotFound, "Group not found by handler and ID: '#{handler.name}', '#{id}'."
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@handler = args.fetch(:handler)
|
14
|
+
@id = args.fetch(:id)
|
15
|
+
@data = args[:data] || {}
|
16
|
+
raise "Invalid ID: #{@id}" if @id.blank?
|
17
|
+
end
|
18
|
+
|
19
|
+
def translations(args = {})
|
20
|
+
translations_list = @handler.translations_for_group(self)
|
21
|
+
|
22
|
+
args.each do |key, value|
|
23
|
+
if key == :finished
|
24
|
+
translations_list = translations_list.select(&:finished?) if value
|
25
|
+
elsif key == :unfinished
|
26
|
+
translations_list = translations_list.select(&:unfinished?) if value
|
27
|
+
else
|
28
|
+
raise "Unknown key: #{key}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
translations_list
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_param
|
36
|
+
id
|
37
|
+
end
|
38
|
+
|
39
|
+
def name
|
40
|
+
@data[:name].presence || id.presence
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"<PeakFlowUtils::GroupService id=\"#{@id}\" name=\"#{name}\">"
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
to_s
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class PeakFlowUtils::HandlersFinderService < PeakFlowUtils::ApplicationService
|
2
|
+
def execute
|
3
|
+
handlers = []
|
4
|
+
|
5
|
+
Dir.foreach("#{File.dirname(__FILE__)}/../../handlers/peak_flow_utils") do |file|
|
6
|
+
match = file.match(/\A(.+)_handler\.rb\Z/)
|
7
|
+
next unless match
|
8
|
+
|
9
|
+
const_name_snake = "#{match[1]}_handler"
|
10
|
+
next if const_name_snake == "application_handler"
|
11
|
+
|
12
|
+
const_name_camel = const_name_snake.camelize
|
13
|
+
|
14
|
+
handler = PeakFlowUtils::HandlerHelper.new(
|
15
|
+
id: const_name_snake,
|
16
|
+
const_name: const_name_camel,
|
17
|
+
name: const_name_camel
|
18
|
+
)
|
19
|
+
|
20
|
+
handlers << handler if handler.instance.enabled?
|
21
|
+
end
|
22
|
+
|
23
|
+
ServicePattern::Response.new(result: handlers)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
class PeakFlowUtils::ModelInspector
|
2
|
+
attr_reader :clazz
|
3
|
+
cattr_accessor :models_loaded
|
4
|
+
|
5
|
+
# Yields a model-inspector for each model found in the application.
|
6
|
+
def self.model_classes
|
7
|
+
# Make sure all models are loaded.
|
8
|
+
load_models
|
9
|
+
|
10
|
+
@scanned = {}
|
11
|
+
@yielded = {}
|
12
|
+
@skip = ["ActiveRecord::SchemaMigration"]
|
13
|
+
|
14
|
+
ArrayEnumerator.new do |yielder|
|
15
|
+
find_subclasses(ActiveRecord::Base) do |model_inspector|
|
16
|
+
next if !model_inspector.clazz.name || @skip.include?(model_inspector.clazz.name)
|
17
|
+
|
18
|
+
yielder << model_inspector
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(clazz)
|
24
|
+
@clazz = clazz
|
25
|
+
end
|
26
|
+
|
27
|
+
def attributes
|
28
|
+
ArrayEnumerator.new do |yielder|
|
29
|
+
@clazz.attribute_names.each do |attribute_name|
|
30
|
+
yielder << PeakFlowUtils::AttributeService.new(self, attribute_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def paperclip_attachments
|
36
|
+
return unless ::Kernel.const_defined?("Paperclip")
|
37
|
+
|
38
|
+
Paperclip::AttachmentRegistry.names_for(@clazz).each do |name|
|
39
|
+
yield name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def money_attributes
|
44
|
+
return if !::Kernel.const_defined?("Money") || !@clazz.respond_to?(:monetized_attributes)
|
45
|
+
|
46
|
+
@clazz.monetized_attributes.each do |attribute|
|
47
|
+
yield attribute[0].to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def globalize_attributes
|
52
|
+
return if !::Kernel.const_defined?("Globalize") || !@clazz.respond_to?(:translated_attribute_names)
|
53
|
+
|
54
|
+
@clazz.translated_attribute_names.each do |attribute|
|
55
|
+
yield attribute.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def snake_name
|
60
|
+
clazz.name.gsub("::", "/").split("/").map(&:underscore).join("/")
|
61
|
+
end
|
62
|
+
|
63
|
+
def class_key
|
64
|
+
"activerecord.models.#{snake_name}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def class_key_one
|
68
|
+
"#{class_key}.one"
|
69
|
+
end
|
70
|
+
|
71
|
+
def class_key_other
|
72
|
+
"#{class_key}.other"
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: Maybe this should yield a ModelInspector::Relationship instead?
|
76
|
+
def relationships
|
77
|
+
@clazz.reflections.each do |key, reflection|
|
78
|
+
yield key, reflection
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def attribute_key(attribute_name)
|
83
|
+
"activerecord.attributes.#{snake_name}.#{attribute_name}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
"<PeakFlowUtils::ModelInspector class-name: \"#{@clazz.name}\">"
|
88
|
+
end
|
89
|
+
|
90
|
+
def inspect
|
91
|
+
to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.find_subclasses(clazz, &blk)
|
95
|
+
return if @scanned[clazz.name]
|
96
|
+
|
97
|
+
@scanned[clazz.name] = true
|
98
|
+
|
99
|
+
clazz.subclasses.each do |subclass|
|
100
|
+
blk.call ::PeakFlowUtils::ModelInspector.new(subclass)
|
101
|
+
find_subclasses(subclass, &blk)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Preloads all models for Rails app and all engines (if they aren't loaded, then they cant be inspected).
|
106
|
+
def self.load_models
|
107
|
+
return false if PeakFlowUtils::ModelInspector.models_loaded
|
108
|
+
|
109
|
+
PeakFlowUtils::ModelInspector.models_loaded = true
|
110
|
+
|
111
|
+
load_models_for(Rails.root)
|
112
|
+
engines.each do |engine|
|
113
|
+
load_models_for(engine.root)
|
114
|
+
end
|
115
|
+
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.engines
|
120
|
+
::Rails::Engine.subclasses.map(&:instance)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Loads models for the given app-directory (Rails-root or engine).
|
124
|
+
def self.load_models_for(root)
|
125
|
+
Dir.glob("#{root}/app/models/**/*.rb") do |model_path|
|
126
|
+
require model_path
|
127
|
+
rescue StandardError => e
|
128
|
+
warn "Could not load model in #{model_path}"
|
129
|
+
warn e.inspect
|
130
|
+
warn e.backtrace
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class PeakFlowUtils::TranslationService
|
2
|
+
attr_reader :default, :dir, :key, :key_show, :file_path, :line_no, :full_path
|
3
|
+
|
4
|
+
def initialize(data)
|
5
|
+
@data = data
|
6
|
+
@dir = data[:dir]
|
7
|
+
@file_path = data[:file_path]
|
8
|
+
@full_path = data[:full_path]
|
9
|
+
@line_no = data[:line_no]
|
10
|
+
@key = data[:key]
|
11
|
+
@key_show = data[:key_show]
|
12
|
+
@default = data[:default]
|
13
|
+
|
14
|
+
raise "Dir wasn't valid: '#{@dir}'." if @dir.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
def last_key
|
18
|
+
key.to_s.split(".").last
|
19
|
+
end
|
20
|
+
|
21
|
+
def key_show_with_fallback
|
22
|
+
@key_show.presence || last_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def array_translation?
|
26
|
+
return true if /\[(\d+)\]\Z/.match?(@key)
|
27
|
+
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def array_key
|
32
|
+
return unless (match = @key.match(/\A(.+)\[(\d+)\]\Z/))
|
33
|
+
|
34
|
+
match[1]
|
35
|
+
end
|
36
|
+
|
37
|
+
def array_no
|
38
|
+
return unless (match = @key.match(/\A(.+)\[(\d+)\]\Z/))
|
39
|
+
|
40
|
+
match[2].to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_param
|
44
|
+
id
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
key
|
49
|
+
end
|
50
|
+
|
51
|
+
def translated_values
|
52
|
+
result = []
|
53
|
+
|
54
|
+
I18n.available_locales.each do |locale|
|
55
|
+
next unless value_for?(locale)
|
56
|
+
|
57
|
+
result << AwesomeTranslations::TranslatedValue.new(
|
58
|
+
file: "#{dir}/#{locale}.yml",
|
59
|
+
key: @key,
|
60
|
+
locale: locale,
|
61
|
+
value: value(locale: locale)
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
68
|
+
def finished?
|
69
|
+
I18n.available_locales.each do |locale|
|
70
|
+
next if value_for?(locale)
|
71
|
+
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def translated_value_for_locale(locale)
|
79
|
+
AwesomeTranslations::TranslatedValue.new(
|
80
|
+
file: "#{dir}/#{locale}.yml",
|
81
|
+
key: @key,
|
82
|
+
locale: locale,
|
83
|
+
value: value_for?(locale) ? value(locale: locale) : ""
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def value_for?(locale)
|
88
|
+
if array_translation?
|
89
|
+
I18n.with_locale(locale) { I18n.exists?(array_key) && I18n.t(array_key)[array_no].present? }
|
90
|
+
else
|
91
|
+
I18n.with_locale(locale) { I18n.exists?(@key) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def value(args = {})
|
96
|
+
locale = (args[:locale] || I18n.locale || I18n.default_locale).to_sym
|
97
|
+
|
98
|
+
return nil unless value_for?(locale)
|
99
|
+
|
100
|
+
if array_translation?
|
101
|
+
I18n.with_locale(locale) { I18n.t(array_key)[array_no] }
|
102
|
+
else
|
103
|
+
I18n.with_locale(locale) { I18n.t(@key) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def file_line_content?
|
108
|
+
return true if @full_path && @line_no && File.exist?(@full_path)
|
109
|
+
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def file_line_content
|
114
|
+
count = 0
|
115
|
+
|
116
|
+
File.open(@full_path, "r") do |fp|
|
117
|
+
fp.each_line do |line|
|
118
|
+
count += 1
|
119
|
+
return line if count == @line_no
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
"<PeakFlowUtils::TranslationService " \
|
128
|
+
"key=\"#{@key}\" " \
|
129
|
+
"dir=\"#{@dir}\" " \
|
130
|
+
"array_translation?=\"#{array_translation?}\" " \
|
131
|
+
"array_key=\"#{array_key}\" " \
|
132
|
+
"array_no=\"#{array_no}\">"
|
133
|
+
end
|
134
|
+
|
135
|
+
def inspect
|
136
|
+
to_s
|
137
|
+
end
|
138
|
+
end
|