peak_flow_utils 0.0.1 → 0.1.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 +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
|