rails-i18nterface 0.1.7 → 0.2.0
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.
- data/README.md +17 -10
- data/app/controllers/rails_i18nterface/application_controller.rb +2 -0
- data/app/controllers/rails_i18nterface/translate_controller.rb +29 -80
- data/app/helpers/rails_i18nterface/application_helper.rb +2 -0
- data/app/helpers/rails_i18nterface/translate_helper.rb +2 -0
- data/app/views/rails_i18nterface/translate/index.html.erb +14 -23
- data/config/routes.rb +2 -0
- data/lib/rails-i18nterface.rb +3 -1
- data/lib/rails-i18nterface/cache.rb +40 -0
- data/lib/rails-i18nterface/engine.rb +2 -0
- data/lib/rails-i18nterface/keys.rb +24 -112
- data/lib/rails-i18nterface/sourcefiles.rb +14 -12
- data/lib/rails-i18nterface/storage.rb +2 -4
- data/lib/rails-i18nterface/utils.rb +51 -0
- data/lib/rails-i18nterface/version.rb +3 -1
- data/lib/rails-i18nterface/yamlfile.rb +15 -17
- data/lib/tasks/rails-i18nterface.rake +1 -0
- data/spec/controllers/translate_controller_spec.rb +18 -33
- data/spec/internal/app/controllers/application_controller.rb +2 -0
- data/spec/internal/app/models/article.rb +8 -2
- data/spec/internal/config/routes.rb +2 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/log/test.log +241 -1608
- data/spec/lib/cache_spec.rb +51 -0
- data/spec/lib/keys_spec.rb +59 -88
- data/spec/lib/sourcefiles_spec.rb +8 -6
- data/spec/lib/storage_spec.rb +2 -0
- data/spec/lib/utils_spec.rb +34 -0
- data/spec/lib/yamlfile_spec.rb +10 -5
- data/spec/requests/search_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -3
- metadata +104 -67
- checksums.yaml +0 -7
- data/app/models/rails_i18nterface/translation.rb +0 -23
- data/db/migrate/20110921112044_create_translations.rb +0 -18
- data/db/migrate/20130422115639_rename_translation_to_namespace.rb +0 -8
- data/lib/rails-i18nterface/log.rb +0 -40
- data/spec/lib/log_spec.rb +0 -47
- data/spec/models/translation_spec.rb +0 -9
data/README.md
CHANGED
@@ -40,11 +40,7 @@ In routes.rb
|
|
40
40
|
```ruby
|
41
41
|
mount RailsI18nterface::Engine => "/translate", :as => "translate_engine"
|
42
42
|
```
|
43
|
-
|
44
|
-
```
|
45
|
-
rake railties:install:migrations
|
46
|
-
rake db:migrate
|
47
|
-
```
|
43
|
+
|
48
44
|
### Protect access
|
49
45
|
|
50
46
|
You may want to protect the translation engine to admin and create a constraint
|
@@ -55,6 +51,11 @@ constraints AdminConstraint.new do
|
|
55
51
|
mount RailsI18nterface::Engine => "/translate", :as => "translate_engine"
|
56
52
|
end
|
57
53
|
end
|
54
|
+
# this second route will be then used if the user is not an admin
|
55
|
+
get 'translate' => redirect do |p, req|
|
56
|
+
req.flash['error'] = I18n.t('errors.permission_denied')
|
57
|
+
"/signin"
|
58
|
+
end
|
58
59
|
```
|
59
60
|
|
60
61
|
Then create a `config/initializers/admin_constraint.rb` containing:
|
@@ -81,16 +82,22 @@ Where `[:en]` and `[:ja, :es, :fr]` could be replaced by locale list of your cho
|
|
81
82
|
## Todo
|
82
83
|
|
83
84
|
* fix the code smell reported by code climate
|
84
|
-
* extract code from the controller to a lib
|
85
|
-
* refactor the libs in a cleaner way
|
86
|
-
* apply rubocop and follow his law
|
85
|
+
* extract code from the controller to a lib (in progress)
|
86
|
+
* refactor the libs in a cleaner way (in progress)
|
87
|
+
* apply rubocop and follow his law (done)
|
87
88
|
* make the application thread-safe
|
88
|
-
* remove those damn global variables
|
89
|
-
* extend testing to refactored libs
|
89
|
+
* remove those damn global variables (in progress)
|
90
|
+
* extend testing to refactored libs (in progress)
|
90
91
|
* change navigation to an ajax-driven reload
|
91
92
|
* add a way to gather .one and .other and .few under same translation line
|
92
93
|
* add support for other i18n backends (gettext)
|
93
94
|
|
95
|
+
## Note for upgrade 0.1.x to 0.2.x
|
96
|
+
|
97
|
+
The database is not used anymore, back to the good old way.
|
98
|
+
So you can remove the table rails_i18nterface_translations (v0.1.7)
|
99
|
+
or translations (< 0.1.7).
|
100
|
+
|
94
101
|
## License
|
95
102
|
|
96
103
|
```
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module RailsI18nterface
|
2
4
|
class TranslateController < RailsI18nterface::ApplicationController
|
3
5
|
|
@@ -8,108 +10,68 @@ module RailsI18nterface
|
|
8
10
|
|
9
11
|
def index
|
10
12
|
@dbvalues = {}
|
11
|
-
@keys =
|
12
|
-
|
13
|
-
@
|
13
|
+
@keys = RailsI18nterface::Keys.new(Rails.root, @from_locale, @to_locale)
|
14
|
+
@files = @keys.files
|
15
|
+
@yaml_keys = @keys.yaml_keys
|
16
|
+
@all_keys = @keys.all_keys
|
17
|
+
@deep_keys = to_deep_hash(@all_keys)
|
14
18
|
filter_by_key_pattern
|
15
19
|
filter_by_text_pattern
|
16
20
|
filter_by_translated_or_changed
|
17
21
|
sort_keys
|
18
22
|
paginate_keys
|
19
|
-
@total_entries = @
|
23
|
+
@total_entries = @all_keys.size
|
24
|
+
@page_title = 'Translate'
|
25
|
+
@show_filters = ['all', 'untranslated', 'translated']
|
20
26
|
end
|
21
27
|
|
22
28
|
def destroy
|
23
|
-
puts params
|
24
|
-
term = RailsI18nterface::Translation.find_by_key(params[:del])
|
25
|
-
if term and term.destroy
|
26
|
-
flash[:success] = "Translations removed from database"
|
27
|
-
else
|
28
|
-
flash[:notice] = "Translations not found in database"
|
29
|
-
end
|
30
29
|
params[:key] = { params[:del] => '' }
|
31
30
|
update
|
32
31
|
end
|
33
32
|
|
34
|
-
def load_db_translations
|
35
|
-
@versions = {}
|
36
|
-
@dbvalues = {@to_locale => {}}
|
37
|
-
(RailsI18nterface::Translation.where(:locale => @to_locale) || []).each do |translation|
|
38
|
-
@versions[translation.key] = translation.updated_at.to_i
|
39
|
-
yaml_value = I18n.backend.send(:lookup, @to_locale, translation.key)
|
40
|
-
if yaml_value && translation.value != yaml_value
|
41
|
-
translation.value = yaml_value
|
42
|
-
RailsI18nterface::Translation.where(key: translation.key).first.update_attribute(:value, yaml_value)
|
43
|
-
end
|
44
|
-
@dbvalues[@to_locale][translation.key] = translation.value
|
45
|
-
@keys << translation.key
|
46
|
-
end
|
47
|
-
@keys.uniq!
|
48
|
-
end
|
49
|
-
|
50
33
|
def export
|
51
34
|
locale = params[:locale].to_sym
|
52
35
|
keys = {locale => I18n.backend.send(:translations)[locale] || {}}
|
53
|
-
RailsI18nterface::Translation.where(:locale => @to_locale).each do |translation|
|
54
|
-
next if !translation.value or translation.value == ''
|
55
|
-
set_nested(keys[locale], translation.key.split('.'), translation.value)
|
56
|
-
end
|
57
36
|
remove_blanks keys
|
58
|
-
|
59
|
-
yaml = RailsI18nterface::Yamlfile.new(nil).keys_to_yaml(keys)
|
37
|
+
yaml = keys_to_yaml(keys)
|
60
38
|
response.headers['Content-Disposition'] = "attachment; filename=#{locale}.yml"
|
61
39
|
render :text => yaml
|
62
40
|
end
|
63
41
|
|
64
42
|
def update
|
65
|
-
RailsI18nterface::Translation.update(@to_locale, params[:key])
|
66
43
|
if I18n.backend.respond_to? :store_translations
|
67
|
-
I18n.backend.store_translations(@to_locale,
|
44
|
+
I18n.backend.store_translations(@to_locale, to_deep_hash(params[:key]))
|
68
45
|
end
|
69
|
-
RailsI18nterface::
|
70
|
-
|
71
|
-
force_init_translations
|
72
|
-
flash[:notice] =
|
46
|
+
yaml = RailsI18nterface::Yamlfile.new(Rails.root, @to_locale)
|
47
|
+
yaml.write_to_file
|
48
|
+
force_init_translations
|
49
|
+
flash[:notice] = 'Translations stored'
|
73
50
|
redirect_to root_path(params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern))
|
74
51
|
end
|
75
52
|
|
76
53
|
def reload
|
77
|
-
|
54
|
+
@keys.reload
|
78
55
|
redirect_to root_path(params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern))
|
79
56
|
end
|
80
57
|
|
81
58
|
private
|
82
59
|
|
83
|
-
def initialize_keys
|
84
|
-
@files = RailsI18nterface::Keys.files
|
85
|
-
keys = (@files.keys.map(&:to_s) + RailsI18nterface::Keys.new.i18n_keys(@from_locale)).uniq
|
86
|
-
keys.reject! do |key|
|
87
|
-
from_text = lookup(@from_locale, key)
|
88
|
-
# When translating from one language to another,
|
89
|
-
# make sure there is a text to translate from.
|
90
|
-
# Always exclude non string translation objects
|
91
|
-
# as we don't support editing them in the UI.
|
92
|
-
(@from_locale != @to_locale && !from_text.present?) ||
|
93
|
-
(from_text.present? && !from_text.is_a?(String))
|
94
|
-
end
|
95
|
-
end
|
96
60
|
|
97
61
|
def lookup(locale, key)
|
98
|
-
|
62
|
+
I18n.backend.send(:lookup, locale, key)
|
99
63
|
end
|
100
64
|
helper_method :lookup
|
101
65
|
|
102
66
|
def filter_by_translated_or_changed
|
103
67
|
params[:filter] ||= 'all'
|
104
68
|
return if params[:filter] == 'all'
|
105
|
-
@
|
69
|
+
@all_keys.reject! do |key|
|
106
70
|
case params[:filter]
|
107
71
|
when 'untranslated'
|
108
72
|
lookup(@to_locale, key).present?
|
109
73
|
when 'translated'
|
110
74
|
lookup(@to_locale, key).blank?
|
111
|
-
when 'changed'
|
112
|
-
old_from_text(key).blank? || lookup(@from_locale, key) == old_from_text(key)
|
113
75
|
else
|
114
76
|
raise "Unknown filter '#{params[:filter]}'"
|
115
77
|
end
|
@@ -118,15 +80,15 @@ module RailsI18nterface
|
|
118
80
|
|
119
81
|
def filter_by_key_pattern
|
120
82
|
return if params[:key_pattern].blank?
|
121
|
-
@
|
83
|
+
@all_keys.reject! do |key|
|
122
84
|
case params[:key_type]
|
123
|
-
when
|
85
|
+
when 'starts_with'
|
124
86
|
if params[:key_pattern] == '.'
|
125
87
|
key.match(/\./)
|
126
88
|
else
|
127
89
|
!key.starts_with?(params[:key_pattern])
|
128
90
|
end
|
129
|
-
when
|
91
|
+
when 'contains'
|
130
92
|
key.index(params[:key_pattern]).nil?
|
131
93
|
else
|
132
94
|
raise "Unknown key_type '#{params[:key_type]}'"
|
@@ -136,7 +98,7 @@ module RailsI18nterface
|
|
136
98
|
|
137
99
|
def filter_by_text_pattern
|
138
100
|
return if params[:text_pattern].blank?
|
139
|
-
@
|
101
|
+
@all_keys.reject! do |key|
|
140
102
|
lookup_key = lookup(@from_locale, key)
|
141
103
|
case params[:text_type]
|
142
104
|
when 'contains'
|
@@ -150,12 +112,12 @@ module RailsI18nterface
|
|
150
112
|
end
|
151
113
|
|
152
114
|
def sort_keys
|
153
|
-
params[:sort_by] ||=
|
115
|
+
params[:sort_by] ||= 'key'
|
154
116
|
case params[:sort_by]
|
155
|
-
when
|
156
|
-
@
|
157
|
-
when
|
158
|
-
@
|
117
|
+
when 'key'
|
118
|
+
@all_keys.sort!
|
119
|
+
when 'text'
|
120
|
+
@all_keys.sort! do |key1, key2|
|
159
121
|
if lookup(@from_locale, key1).present? && lookup(@from_locale, key2).present?
|
160
122
|
lookup(@from_locale, key1).to_s.downcase <=> lookup(@from_locale, key2).to_s.downcase
|
161
123
|
elsif lookup(@from_locale, key1).present?
|
@@ -171,7 +133,7 @@ module RailsI18nterface
|
|
171
133
|
|
172
134
|
def paginate_keys
|
173
135
|
params[:page] ||= 1
|
174
|
-
@paginated_keys = @
|
136
|
+
@paginated_keys = @all_keys[offset, per_page]
|
175
137
|
end
|
176
138
|
|
177
139
|
def offset
|
@@ -204,18 +166,5 @@ module RailsI18nterface
|
|
204
166
|
@to_locale = session[:to_locale].to_sym
|
205
167
|
end
|
206
168
|
|
207
|
-
def old_from_text(key)
|
208
|
-
return @old_from_text[key] if @old_from_text && @old_from_text[key]
|
209
|
-
@old_from_text = {}
|
210
|
-
text = key.split(".").reduce(log_hash) do |hash, k|
|
211
|
-
hash ? hash[k] : nil
|
212
|
-
end
|
213
|
-
@old_from_text[key] = text
|
214
|
-
end
|
215
|
-
helper_method :old_from_text
|
216
|
-
|
217
|
-
def log_hash
|
218
|
-
@log_hash ||= RailsI18nterface::Log.new(@from_locale, @to_locale, {}).read
|
219
|
-
end
|
220
169
|
end
|
221
170
|
end
|
@@ -1,29 +1,21 @@
|
|
1
|
-
<%
|
2
|
-
@page_title = "Translate"
|
3
|
-
show_filters = ["all", "untranslated", "translated"]
|
4
|
-
show_filters << "changed" if @from_locale != @to_locale
|
5
|
-
%>
|
6
1
|
<%= form_tag(params, :method => :get, :name => 'filter_form') do %>
|
7
2
|
<%= hidden_field_tag(:filter, params[:filter]) %>
|
8
3
|
<%= hidden_field_tag(:sort_by, params[:sort_by]) %>
|
9
4
|
<div id="top">
|
10
|
-
|
11
|
-
<
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
</h1>
|
26
|
-
<% end %>
|
5
|
+
<h1>
|
6
|
+
<div class="right">
|
7
|
+
<%= select_tag(:from_locale, options_for_select(I18n.available_locales, @from_locale.to_sym)) %> <span>to</span>
|
8
|
+
<%= select_tag(:to_locale, options_for_select(I18n.available_locales, @to_locale.to_sym)) %>
|
9
|
+
<%= submit_tag "Display" %>
|
10
|
+
</div>
|
11
|
+
<%= link_to '.. /', '../' %>
|
12
|
+
<%= link_to @page_title, root_path %></a>
|
13
|
+
<div class="center">
|
14
|
+
<label>Show:</label> <%= simple_filter(@show_filters).html_safe %>
|
15
|
+
Found <strong><%= @total_entries %></strong> messages
|
16
|
+
<%= link_to "Reload messages", translate_reload_path(params) %>
|
17
|
+
</div>
|
18
|
+
</h1>
|
27
19
|
<% flash.each do |key, msg| %>
|
28
20
|
<div class="flash" id="<%= key %>"><%= msg %></div>
|
29
21
|
<% end %>
|
@@ -78,7 +70,6 @@
|
|
78
70
|
%>
|
79
71
|
<div class="translation">
|
80
72
|
<p class="edit-form">
|
81
|
-
<%= hidden_field_tag("version[#{key}]", @versions[key] || '0') %>
|
82
73
|
<% if n_lines > 1 %>
|
83
74
|
<div class="right">
|
84
75
|
<% if @files[key] %>
|
data/config/routes.rb
CHANGED
data/lib/rails-i18nterface.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'rails-i18nterface/engine'
|
2
4
|
require 'rails-i18nterface/utils'
|
5
|
+
require 'rails-i18nterface/cache'
|
3
6
|
require 'rails-i18nterface/yamlfile'
|
4
7
|
require 'rails-i18nterface/sourcefiles'
|
5
8
|
require 'rails-i18nterface/keys'
|
6
|
-
require 'rails-i18nterface/log'
|
7
9
|
require 'rails-i18nterface/storage'
|
8
10
|
|
9
11
|
module RailsI18nterface
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RailsI18nterface
|
4
|
+
module Cache
|
5
|
+
|
6
|
+
def cache_save(obj, uri, options={})
|
7
|
+
FileUtils.rm uri if File.exists? uri
|
8
|
+
File.open(uri, 'wb') do |f|
|
9
|
+
Marshal.dump(obj, f)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def cache_load(uri, file, &process)
|
14
|
+
mtime = File.mtime(file)
|
15
|
+
if cached?(uri) && uptodate?(uri, file)
|
16
|
+
File.open(uri) do |f|
|
17
|
+
Marshal.load f
|
18
|
+
end
|
19
|
+
else
|
20
|
+
if block_given?
|
21
|
+
obj = yield
|
22
|
+
cache_save(obj, uri)
|
23
|
+
File.utime(mtime, mtime, uri)
|
24
|
+
obj
|
25
|
+
else
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def cached?(uri)
|
32
|
+
File.file? uri
|
33
|
+
end
|
34
|
+
|
35
|
+
def uptodate?(uri, file)
|
36
|
+
File.mtime(uri) == File.mtime(file)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -1,57 +1,50 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
3
|
module RailsI18nterface
|
4
4
|
class Keys
|
5
5
|
|
6
|
-
|
7
|
-
def self.files
|
8
|
-
@files ||= new.files
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.names
|
12
|
-
@names || new.names
|
13
|
-
end
|
14
|
-
# Allows flushing of the files cache
|
15
|
-
def self.files=(files)
|
16
|
-
@files = files
|
17
|
-
end
|
6
|
+
include Utils
|
18
7
|
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
alias_method :to_hash, :files
|
8
|
+
attr_accessor :files, :keys
|
9
|
+
attr_reader :yaml_keys, :all_keys
|
23
10
|
|
24
|
-
def
|
25
|
-
@
|
11
|
+
def initialize(root_dir, from, to)
|
12
|
+
@root_dir = root_dir
|
13
|
+
@files = RailsI18nterface::Sourcefiles.extract_files(root_dir)
|
14
|
+
@yaml_keys = i18n_keys(I18n.default_locale)
|
15
|
+
@from_locale = from
|
16
|
+
@to_locale = to
|
17
|
+
@all_keys = (@files.keys.map(&:to_s) + @yaml_keys).uniq
|
26
18
|
end
|
27
|
-
alias_method :to_tree, :names
|
28
19
|
|
29
|
-
def
|
30
|
-
files.
|
20
|
+
def reload
|
21
|
+
@files = RailsI18nterface::Sourcefiles.extract_files(root_dir)
|
22
|
+
@yaml_keys = i18n_keys(I18n.default_locale)
|
23
|
+
@all_keys = (@files.keys.map(&:to_s) + @yaml_keys).uniq
|
31
24
|
end
|
32
|
-
alias_method :to_a, :keys
|
33
25
|
|
34
26
|
def i18n_keys(locale)
|
35
27
|
I18n.backend.send(:init_translations) unless I18n.backend.initialized?
|
36
|
-
|
28
|
+
to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort
|
37
29
|
end
|
38
30
|
|
39
31
|
def untranslated_keys
|
40
|
-
self.class.translated_locales.reduce({}) do |
|
41
|
-
|
42
|
-
I18n.backend.send(:lookup,
|
32
|
+
self.class.translated_locales.reduce({}) do |a, e|
|
33
|
+
a[e] = i18n_keys(I18n.default_locale).map do |key|
|
34
|
+
I18n.backend.send(:lookup, e, key).nil? ? key : nil
|
43
35
|
end.compact
|
44
|
-
|
36
|
+
a
|
45
37
|
end
|
46
38
|
end
|
47
39
|
|
48
40
|
def missing_keys
|
49
41
|
locale = I18n.default_locale
|
42
|
+
filepath = Dir.glob(File.join(@root_dir, 'config', 'locales', '**', "#{locale}.yml"))
|
50
43
|
yaml_keys = {}
|
51
|
-
yaml_keys =
|
52
|
-
|
44
|
+
yaml_keys = filepath.reduce({}) do |a, e|
|
45
|
+
a = a.deep_merge(Yamlfile.new(@root_dir, locale).read[locale.to_s])
|
53
46
|
end
|
54
|
-
files.reject { |key, file|
|
47
|
+
@files.keys.reject { |key, file| contains_key?(yaml_keys, key) }
|
55
48
|
end
|
56
49
|
|
57
50
|
def self.translated_locales
|
@@ -60,86 +53,5 @@ module RailsI18nterface
|
|
60
53
|
end
|
61
54
|
end
|
62
55
|
|
63
|
-
# Checks if a nested hash contains the keys in dot separated I18n key.
|
64
|
-
#
|
65
|
-
# Example:
|
66
|
-
#
|
67
|
-
# hash = {
|
68
|
-
# :foo => {
|
69
|
-
# :bar => {
|
70
|
-
# :baz => 1
|
71
|
-
# }
|
72
|
-
# }
|
73
|
-
# }
|
74
|
-
#
|
75
|
-
# contains_key?("foo", key) # => true
|
76
|
-
# contains_key?("foo.bar", key) # => true
|
77
|
-
# contains_key?("foo.bar.baz", key) # => true
|
78
|
-
# contains_key?("foo.bar.baz.bla", key) # => false
|
79
|
-
#
|
80
|
-
def self.contains_key?(hash, key)
|
81
|
-
keys = key.to_s.split('.')
|
82
|
-
return false if keys.empty?
|
83
|
-
!keys.reduce(HashWithIndifferentAccess.new(hash)) do |memo, k|
|
84
|
-
memo.is_a?(Hash) ? memo.try(:[], k) : nil
|
85
|
-
end.nil?
|
86
|
-
end
|
87
|
-
|
88
|
-
# Convert something like:
|
89
|
-
#
|
90
|
-
# {
|
91
|
-
# :pressrelease => {
|
92
|
-
# :label => {
|
93
|
-
# :one => "Pressmeddelande"
|
94
|
-
# }
|
95
|
-
# }
|
96
|
-
# }
|
97
|
-
#
|
98
|
-
# to:
|
99
|
-
#
|
100
|
-
# {'pressrelease.label.one' => "Pressmeddelande"}
|
101
|
-
#
|
102
|
-
def self.to_shallow_hash(hash)
|
103
|
-
hash.reduce({}) do |shallow_hash, (key, value)|
|
104
|
-
if value.is_a?(Hash)
|
105
|
-
to_shallow_hash(value).each do |sub_key, sub_value|
|
106
|
-
shallow_hash[[key, sub_key].join('.')] = sub_value
|
107
|
-
end
|
108
|
-
else
|
109
|
-
shallow_hash[key.to_s] = value
|
110
|
-
end
|
111
|
-
shallow_hash
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# Convert something like:
|
116
|
-
#
|
117
|
-
# {'pressrelease.label.one' => "Pressmeddelande"}
|
118
|
-
#
|
119
|
-
# to:
|
120
|
-
#
|
121
|
-
# {
|
122
|
-
# :pressrelease => {
|
123
|
-
# :label => {
|
124
|
-
# :one => "Pressmeddelande"
|
125
|
-
# }
|
126
|
-
# }
|
127
|
-
# }
|
128
|
-
def self.to_deep_hash(hash)
|
129
|
-
hash.reduce({}) do |deep_hash, (key, value)|
|
130
|
-
keys = key.to_s.split('.').reverse
|
131
|
-
leaf_key = keys.shift
|
132
|
-
key_hash = keys.reduce({leaf_key.to_sym => value}) { |h, k| { k.to_sym => h } }
|
133
|
-
deep_merge!(deep_hash, key_hash)
|
134
|
-
deep_hash
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
|
139
|
-
def self.deep_merge!(hash1, hash2)
|
140
|
-
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
141
|
-
hash1.merge!(hash2, &merger)
|
142
|
-
end
|
143
|
-
|
144
56
|
end
|
145
57
|
end
|