weeler 1.4.0 → 1.5.1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -3
  3. data/CHANGELOG.md +24 -0
  4. data/Rakefile +4 -0
  5. data/app/controllers/weeler/translations_controller.rb +13 -7
  6. data/app/views/weeler/translations/_translation.html.haml +2 -2
  7. data/app/views/weeler/translations/edit.html.haml +3 -3
  8. data/app/views/weeler/translations/new.html.haml +2 -2
  9. data/app/views/weeler/translations/usage_stats.html.haml +10 -4
  10. data/lib/generators/weeler/templates/migrations/create_weeler_locks.rb +14 -0
  11. data/lib/generators/weeler/templates/migrations/create_weeler_translation_stats.rb +11 -0
  12. data/lib/i18n/backend/weeler.rb +15 -6
  13. data/lib/i18n/backend/weeler/lock.rb +78 -0
  14. data/lib/i18n/backend/weeler/translation_stat.rb +25 -0
  15. data/lib/i18n/backend/weeler/usage_logger.rb +17 -1
  16. data/lib/weeler/action_controller/acts/restful.rb +1 -1
  17. data/lib/weeler/engine.rb +1 -1
  18. data/lib/weeler/version.rb +2 -2
  19. data/spec/.gitignore +21 -0
  20. data/spec/dummy/config/database.yml +2 -24
  21. data/spec/dummy/db/migrate/20160330161101_create_weeler_locks.rb +14 -0
  22. data/spec/dummy/db/migrate/20160330192005_create_weeler_translation_stats.rb +11 -0
  23. data/spec/dummy/db/schema.rb +31 -11
  24. data/spec/dummy/log/development.log +780 -0
  25. data/spec/spec_helper.rb +1 -1
  26. data/spec/weeler/action_controller/acts/restful_spec.rb +1 -1
  27. data/spec/weeler/i18n/backend/weeler/lock_spec.rb +89 -0
  28. data/spec/weeler/i18n/backend/weeler/usage_logger_spec.rb +34 -0
  29. data/spec/weeler/i18n/backend/weeler_spec.rb +22 -0
  30. data/weeler.gemspec +2 -2
  31. metadata +18 -8
  32. data/spec/dummy/db/development.sqlite3 +0 -0
  33. data/spec/dummy/db/test.sqlite3 +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04354c614713ac3f01bbd9ef74db3d3adfbf6e5e
4
- data.tar.gz: b7cb66aa043d0f4474d030fc8a3098c2f110eeb4
3
+ metadata.gz: 21fd389096c8af80e13c46bf777233d15188fa71
4
+ data.tar.gz: 783c33428045e4d05b7e76fc10a991cafc3f9b2e
5
5
  SHA512:
6
- metadata.gz: 3995b5e005fae4e1d03fa0bcbee009fd7cfa0ace18d0be818250c690b6afec317ed9ee0b31f213a19c112308463aa039e1be74ea53dd420162833e6ff7e7cc8f
7
- data.tar.gz: aca2e0510b49b00a85d99a8329eec36874b10105ead3cd20b13da590a68f38b0c43056ea6424265a3033c85c575b731b944044a02917e2124380416a02f31c84
6
+ metadata.gz: 39c2ceb91177c876eadeb18b9e03b86fc8367c33a48cc81f4b2e627741290816c5d8ecd8c20188c87e1f776e3e6df7f1f16e19f154007464e4200d9b25123ee1
7
+ data.tar.gz: e9602c77a0ea9738ae4eb0c8dd91c98bdfb228a594e9ead83d41b0bcbf4bb0a799f19fabeb8c2c479c0e07b0be4b148b0da8b19388d4e8bd47edfb8954f187e4
@@ -1,4 +1,11 @@
1
1
  language: ruby
2
+ before_install:
3
+ - rvm get head
4
+ services:
5
+ - postgresql
6
+ sudo: false
7
+ before_script:
8
+ - psql -c 'create database travis_ci_test;' -U postgres
2
9
  rvm:
3
10
  - "2.0.0"
4
11
  - "2.1.0"
@@ -11,7 +18,10 @@ rvm:
11
18
  - "2.2.0"
12
19
  - "2.2.1"
13
20
  - "2.2.2"
14
- - "jruby"
15
- - "rbx-2.4.1"
21
+ - "2.2.3"
22
+ - "2.2.4"
23
+ - "2.3.0"
16
24
  # uncomment this line if your project needs to run something other than `rake`:
17
- script: bundle exec rspec spec
25
+ script:
26
+ - RAILS_ENV=test bundle exec rake db:migrate --trace
27
+ - bundle exec rspec spec
@@ -1,3 +1,27 @@
1
+ ## 1.5.1
2
+
3
+ * Fixed version number
4
+
5
+ ### Contributors
6
+
7
+ * Artis Raugulis
8
+
9
+ ## 1.4.0
10
+
11
+ * Added translation usage stats
12
+ * Fixed a transliteration bug
13
+
14
+ ### Contributors
15
+
16
+ * Artis Raugulis
17
+
18
+ ## 1.5.0
19
+
20
+ * Added Lock
21
+ * Added translation usage stats export
22
+ * Dropped jruby support
23
+ * Dropped rbx suport
24
+
1
25
  ## 1.4.0
2
26
 
3
27
  * Added translation usage stats
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
+ Bundler::GemHelper.install_tasks
2
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
3
+ load 'rails/tasks/engine.rake'
4
+
1
5
  require "bundler/gem_tasks"
@@ -20,7 +20,7 @@ module Weeler
20
20
 
21
21
  if @translation.save
22
22
  Settings.i18n_updated_at = Time.now
23
- redirect_to edit_weeler_translation_path(@translation), flash: {success: "Translation saved."}
23
+ redirect_to ({ action: :edit, id: @translation }), flash: { success: "Translation saved." }
24
24
  else
25
25
  flash.now[:error] = "Errors in saving."
26
26
  render :edit
@@ -33,7 +33,7 @@ module Weeler
33
33
  if @translation.update_attributes(translation_params)
34
34
  Settings.i18n_updated_at = Time.now
35
35
 
36
- redirect_to edit_weeler_translation_path(@translation), flash: {success: "Translation updated."}
36
+ redirect_to ({ action: :edit, id: @translation }), flash: { success: "Translation updated." }
37
37
  else
38
38
  flash.now[:error] = "Errors in updating."
39
39
  render :edit
@@ -46,13 +46,19 @@ module Weeler
46
46
 
47
47
  Settings.i18n_updated_at = Time.now
48
48
 
49
- redirect_to weeler_translations_path, flash: {success: "Translation succesfully removed."}
49
+ redirect_to ({ action: :index }), flash: {success: "Translation succesfully removed."}
50
50
  end
51
51
 
52
52
  def usage_stats
53
53
  @used_keys = []
54
- Weeler.i18n_cache.instance_variable_get(:@data).keys.each do |key|
55
- @used_keys << [key, Weeler.i18n_cache.read(key)] if key.start_with?('usage_stats')
54
+ if Settings.log_key_usage == 'dump'
55
+ I18n::Backend::Weeler::TranslationStat.all.each do |translation_stat|
56
+ @used_keys << [translation_stat.key, translation_stat.usage_count]
57
+ end
58
+ else
59
+ Weeler.i18n_cache.instance_variable_get(:@data).keys.each do |key|
60
+ @used_keys << [key, Weeler.i18n_cache.read(key)] if key.start_with?('usage_stats')
61
+ end
56
62
  end
57
63
  end
58
64
 
@@ -72,9 +78,9 @@ module Weeler
72
78
 
73
79
  Settings.i18n_updated_at = Time.now
74
80
 
75
- redirect_to weeler_translations_path, flash: {success: "Translations succesfully imported."}
81
+ redirect_to ({ action: :index }), flash: {success: "Translations succesfully imported."}
76
82
  else
77
- redirect_to weeler_translations_path, flash: {success: "No file choosen"}
83
+ redirect_to ({ action: :index }), flash: {success: "No file choosen"}
78
84
  end
79
85
  end
80
86
 
@@ -8,5 +8,5 @@
8
8
  %td= translation.interpolations
9
9
  %td.text-center= translation.created_at.strftime("%d/%m/%Y")
10
10
  %td
11
- = link_to 'Edit', edit_weeler_translation_path(translation.id), class: 'btn btn-default'
12
- = link_to 'Remove', weeler_translation_path(translation), data: { confirm: 'Are you sure you want to remove?' }, method: :delete, class: 'btn btn-danger'
11
+ = link_to 'Edit', { action: :edit, id: translation.id }, class: 'btn btn-default'
12
+ = link_to 'Remove', { action: :destroy, id: translation }, data: { confirm: 'Are you sure you want to remove?' }, method: :delete, class: 'btn btn-danger'
@@ -6,9 +6,9 @@
6
6
  .edit_user.container
7
7
  .row
8
8
  .col-lg-12.col-md-12
9
- = form_for @translation, {url: weeler_translation_path(@translation), html: {class: "form-horizontal", role: "form"}} do |f|
9
+ = form_for @translation, {url: { action: :update, id: @translation }, html: {class: "form-horizontal", role: "form"}} do |f|
10
10
  = render partial: "form", locals: {translation: @translation, f: f}
11
11
  %p.text-center
12
12
  %button.btn.btn-primary{type: "submit"} Save
13
- %a.btn.btn-link{href: weeler_translations_path} Cancel
14
- = link_to 'Remove', weeler_translation_path(@translation), :confirm => "Are you sure you want remove?", :method => :delete, :class => "btn btn-danger"
13
+ = link_to 'Cancel', { action: :index }, class: 'btn btn-link'
14
+ = link_to 'Remove', { action: :destroy, id: @translation}, :confirm => "Are you sure you want remove?", :method => :delete, :class => "btn btn-danger"
@@ -6,8 +6,8 @@
6
6
  .edit_user.container
7
7
  .row
8
8
  .col-lg-12.col-md-12
9
- = form_for @translation, {url: weeler_translations_path, html: {class: "form-horizontal", role: "form"}} do |f|
9
+ = form_for @translation, {url: { action: :create }, html: {class: "form-horizontal", role: "form"}} do |f|
10
10
  = render partial: "form", locals: {translation: @translation, f: f}
11
11
  %p.text-center
12
12
  %button.btn.btn-primary{type: "submit"} Save
13
- %a.btn.btn-link{href: weeler_translations_path} Cancel
13
+ = link_to 'Cancel', { action: :index }, class: 'btn btn-link'
@@ -22,7 +22,13 @@
22
22
  %th text
23
23
  %tbody
24
24
  - @used_keys.each do |key, usage|
25
- %tr
26
- %td= usage
27
- %td= key.to_s.gsub('usage_stats/en/', '')
28
- %td= t(key.to_s.gsub('usage_stats/en/', ''))
25
+ - begin
26
+ %tr
27
+ %td= usage
28
+ %td= key.to_s.gsub('usage_stats/en/', '')
29
+ %td= CGI::unescapeHTML(CGI::escapeHTML(t(key.to_s.gsub('usage_stats/en/', ''))))
30
+ - rescue => e
31
+ %tr
32
+ %td= "err #{usage}"
33
+ %td= key
34
+ %td= e.message
@@ -0,0 +1,14 @@
1
+ class CreateWeelerLocks < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :weeler_locks do |t|
4
+ t.string :name, :limit => 40
5
+ t.timestamps
6
+ end
7
+ add_index :weeler_locks, :name, :unique => true
8
+ end
9
+
10
+ def self.down
11
+ remove_index :weeler_locks, :column => :name
12
+ drop_table :weeler_locks
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ class CreateWeelerTranslationStats < ActiveRecord::Migration
2
+ def change
3
+ create_table :weeler_translation_stats do |t|
4
+ t.string :key
5
+ t.integer :usage_count, default: 0
6
+
7
+ t.timestamps
8
+ end
9
+ add_index :weeler_translation_stats, :key
10
+ end
11
+ end
@@ -5,6 +5,8 @@ require 'i18n/backend/weeler/html_checker'
5
5
  require 'i18n/backend/weeler/exporter'
6
6
  require 'i18n/backend/weeler/importer'
7
7
  require 'i18n/backend/weeler/usage_logger'
8
+ require 'i18n/backend/weeler/translation_stat'
9
+ require 'i18n/backend/weeler/lock'
8
10
 
9
11
  module I18n
10
12
  module Backend
@@ -24,12 +26,14 @@ module I18n
24
26
 
25
27
  PLURAL_KEYS = ["zero", "one", "other"]
26
28
 
27
- autoload :HtmlChecker, 'i18n/backend/weeler/html_checker'
28
- autoload :Translation, 'i18n/backend/weeler/dedupe'
29
- autoload :Translation, 'i18n/backend/weeler/translation'
30
- autoload :Exporter, 'i18n/backend/weeler/exporter'
31
- autoload :Importer, 'i18n/backend/weeler/importer'
32
- autoload :UsageLogger, 'i18n/backend/weeler/usage_logger'
29
+ autoload :HtmlChecker, 'i18n/backend/weeler/html_checker'
30
+ autoload :Translation, 'i18n/backend/weeler/dedupe'
31
+ autoload :Translation, 'i18n/backend/weeler/translation'
32
+ autoload :Exporter, 'i18n/backend/weeler/exporter'
33
+ autoload :Importer, 'i18n/backend/weeler/importer'
34
+ autoload :UsageLogger, 'i18n/backend/weeler/usage_logger'
35
+ autoload :TranslationStat, 'i18n/backend/weeler/translation_stat'
36
+ autoload :Lock, 'i18n/backend/weeler/lock'
33
37
 
34
38
  module Implementation
35
39
  include Base, Flatten
@@ -72,9 +76,14 @@ module I18n
72
76
 
73
77
  # log locale/key usage for statistics
74
78
  if Settings.log_key_usage == 'true'
79
+ i18n_cache.delete([:dump_usage_stats, Process.pid])
75
80
  log_key_usage(locale, key)
76
81
  end
77
82
 
83
+ if Settings.log_key_usage == 'dump'
84
+ dump_key_usage
85
+ end
86
+
78
87
  return nil if i18n_cache.read([:missing, [locale, key]])
79
88
 
80
89
  keys = expand_keys key
@@ -0,0 +1,78 @@
1
+ require 'active_record'
2
+
3
+ module I18n
4
+ module Backend
5
+ # Weeler model used to store locks
6
+ #
7
+ # This model expects a table like the following to be already set up in
8
+ # your the database:
9
+ #
10
+ # def self.up
11
+ # create_table :weeler_locks do |t|
12
+ # t.string :name, :limit => 40
13
+ # t.timestamps
14
+ # end
15
+ # add_index :weeler_locks, :name, :unique => true
16
+ # end
17
+ #
18
+ # def self.down
19
+ # remove_index :weeler_locks, :column => :name
20
+ # drop_table :weeler_locks
21
+ # end
22
+ #
23
+ class Weeler
24
+ class Lock < ActiveRecord::Base
25
+
26
+ self.table_name = 'weeler_locks'
27
+
28
+ def self.acquire(name)
29
+ already_acquired = definitely_acquired?(name)
30
+
31
+ if already_acquired
32
+ yield
33
+ else
34
+ begin
35
+ create(:name => name) unless find_by(name: name)
36
+ rescue ActiveRecord::StatementInvalid
37
+ # concurrent create is okay
38
+ end
39
+
40
+ begin
41
+ result = nil
42
+ transaction do
43
+ self.lock(true).find_by(name: name) # this is the call that will block
44
+ acquired_lock(name)
45
+ result = yield
46
+ end
47
+
48
+ result
49
+ ensure
50
+ maybe_released_lock(name)
51
+ end
52
+ end
53
+ end
54
+
55
+ # if true, the lock is acquired
56
+ # if false, the lock might still be acquired, because we were in another db transaction
57
+ def self.definitely_acquired?(name)
58
+ !!Thread.current[:definitely_acquired_locks] and Thread.current[:definitely_acquired_locks].has_key?(name)
59
+ end
60
+
61
+ def self.acquired_lock(name)
62
+ logger.debug("Acquired lock '#{name}'")
63
+ Thread.current[:definitely_acquired_locks] ||= {}
64
+ Thread.current[:definitely_acquired_locks][name] = true
65
+ end
66
+
67
+ def self.maybe_released_lock(name)
68
+ logger.debug("Released lock '#{name}' (if we are not in a bigger transaction)")
69
+ Thread.current[:definitely_acquired_locks] ||= {}
70
+ Thread.current[:definitely_acquired_locks].delete(name)
71
+ end
72
+
73
+ private_class_method :acquired_lock, :maybe_released_lock
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_record'
2
+
3
+ module I18n
4
+ module Backend
5
+ # Weeler model used to store translation key usage statistics
6
+ #
7
+ # This model expects a table like the following to be already set up in
8
+ # your the database:
9
+ #
10
+ # create_table :weeler_translation_stats do |t|
11
+ # t.string :key
12
+ # t.integer :usage_count, default: 0
13
+ # end
14
+ #
15
+ class Weeler
16
+ class TranslationStat < ::ActiveRecord::Base
17
+
18
+ self.table_name = 'weeler_translation_stats'
19
+
20
+ validates :key, uniqueness: true
21
+ validates :key, :usage_count, presence: true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -11,7 +11,23 @@ module I18n
11
11
  value = existing.present? ? (existing.to_i + 1) : 1
12
12
  i18n_cache.write [:usage_stats, [locale, key]], value
13
13
  end
14
-
14
+
15
+ def dump_key_usage
16
+ already_dumped = i18n_cache.read([:dump_usage_stats, Process.pid]).present?
17
+ unless already_dumped
18
+ Weeler::Lock.acquire('usage_stats_dump') do
19
+ i18n_cache.instance_variable_get(:@data).keys.each do |key|
20
+ if key.start_with?('usage_stats')
21
+ translation_stat = TranslationStat.find_or_create_by(key: key.gsub('usage_stats/en/', ''))
22
+ translation_stat.usage_count += i18n_cache.read(key).to_i
23
+ translation_stat.save!
24
+ end
25
+ end
26
+ i18n_cache.write [:dump_usage_stats, Process.pid], Process.pid
27
+ end
28
+ end
29
+ end
30
+
15
31
  Weeler.send(:include, UsageLogger)
16
32
  end
17
33
  end
@@ -118,7 +118,7 @@ module Weeler
118
118
  permited_params.call(params)
119
119
  elsif permited_params.blank?
120
120
  warning_suggestion = params[parameterized_name.to_sym].is_a?(Hash) ? params[parameterized_name.to_sym].keys.map{ |k| k.to_sym } : "permit_params:"
121
- warn "[UNPERMITED PARAMS] To permiting #{params[parameterized_name.to_sym].inspect} params, add 'permit_params: #{warning_suggestion}' option to 'acts_as_restful'"
121
+ warn "[UNPERMITED PARAMS] To permit #{params[parameterized_name.to_sym].inspect} params, add 'permit_params: #{warning_suggestion}' option to 'acts_as_restful'"
122
122
  else
123
123
  params.require(parameterized_name.to_sym).permit(permited_params)
124
124
  end
@@ -10,7 +10,7 @@ module Weeler
10
10
  config.weeler = Weeler
11
11
 
12
12
  config.i18n.available_locales = [:en] unless config.i18n.available_locales.present?
13
-
13
+ config.active_record.raise_in_transactional_callbacks = true
14
14
  config.assets.precompile += ["weeler/init.js", "weeler/init.css"]
15
15
 
16
16
  # Load extend Rails classes
@@ -1,8 +1,8 @@
1
1
  module Weeler
2
2
  module VERSION
3
3
  MAJOR = 1
4
- MINOR = 4
5
- TINY = 0
4
+ MINOR = 5
5
+ TINY = 1
6
6
  PRE = nil
7
7
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
8
8
  end
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .coveralls.yml
19
+ .DS_Store
20
+ spec/dummy/log/test.log
21
+ rspec.html
@@ -1,25 +1,3 @@
1
- # SQLite version 3.x
2
- # gem install sqlite3
3
- #
4
- # Ensure the SQLite 3 gem is defined in your Gemfile
5
- # gem 'sqlite3'
6
- development:
7
- adapter: sqlite3
8
- database: db/development.sqlite3
9
- pool: 5
10
- timeout: 5000
11
-
12
- # Warning: The database defined as "test" will be erased and
13
- # re-generated from your development database when you run "rake".
14
- # Do not set this db to the same as development or production.
15
1
  test:
16
- adapter: sqlite3
17
- database: db/test.sqlite3
18
- pool: 5
19
- timeout: 5000
20
-
21
- production:
22
- adapter: sqlite3
23
- database: db/production.sqlite3
24
- pool: 5
25
- timeout: 5000
2
+ adapter: postgresql
3
+ database: travis_ci_test