i18n-tasks 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -4
  3. data/CHANGES.md +7 -0
  4. data/README.md +10 -14
  5. data/i18n-tasks.gemspec +1 -1
  6. data/lib/i18n/tasks.rb +0 -2
  7. data/lib/i18n/tasks/base_task.rb +4 -2
  8. data/lib/i18n/tasks/commands.rb +14 -14
  9. data/lib/i18n/tasks/configuration.rb +10 -2
  10. data/lib/i18n/tasks/console_context.rb +73 -0
  11. data/lib/i18n/tasks/data.rb +0 -47
  12. data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +6 -1
  13. data/lib/i18n/tasks/data/file_system_base.rb +1 -1
  14. data/lib/i18n/tasks/data/router/conservative_router.rb +5 -5
  15. data/lib/i18n/tasks/data/router/pattern_router.rb +2 -2
  16. data/lib/i18n/tasks/data/tree/node.rb +47 -36
  17. data/lib/i18n/tasks/data/tree/nodes.rb +0 -4
  18. data/lib/i18n/tasks/data/tree/siblings.rb +54 -9
  19. data/lib/i18n/tasks/data/tree/traversal.rb +62 -23
  20. data/lib/i18n/tasks/fill_tasks.rb +29 -21
  21. data/lib/i18n/tasks/ignore_keys.rb +1 -1
  22. data/lib/i18n/tasks/key_pattern_matching.rb +17 -0
  23. data/lib/i18n/tasks/missing_keys.rb +39 -44
  24. data/lib/i18n/tasks/plural_keys.rb +14 -1
  25. data/lib/i18n/tasks/reports/base.rb +28 -8
  26. data/lib/i18n/tasks/reports/spreadsheet.rb +9 -8
  27. data/lib/i18n/tasks/reports/terminal.rb +33 -29
  28. data/lib/i18n/tasks/scanners/base_scanner.rb +22 -14
  29. data/lib/i18n/tasks/scanners/pattern_scanner.rb +2 -1
  30. data/lib/i18n/tasks/unused_keys.rb +13 -13
  31. data/lib/i18n/tasks/used_keys.rb +39 -38
  32. data/lib/i18n/tasks/version.rb +1 -1
  33. data/spec/i18n_tasks_spec.rb +41 -40
  34. data/spec/locale_tree/siblings_spec.rb +26 -1
  35. data/spec/support/i18n_tasks_output_matcher.rb +4 -1
  36. data/spec/support/trees.rb +6 -1
  37. data/spec/used_keys_spec.rb +23 -15
  38. metadata +4 -11
  39. data/lib/i18n/tasks/file_structure.rb +0 -19
  40. data/lib/i18n/tasks/key.rb +0 -48
  41. data/lib/i18n/tasks/key/key_group.rb +0 -45
  42. data/lib/i18n/tasks/key/match_pattern.rb +0 -24
  43. data/lib/i18n/tasks/key/usages.rb +0 -12
  44. data/lib/i18n/tasks/key_group.rb +0 -68
  45. data/spec/key_group_spec.rb +0 -49
@@ -2,51 +2,52 @@
2
2
  require 'find'
3
3
  require 'i18n/tasks/scanners/pattern_with_scope_scanner'
4
4
 
5
- module I18n::Tasks::UsedKeys
5
+ module I18n::Tasks
6
+ module UsedKeys
6
7
 
7
- # find all keys in the source (relative keys are absolutized)
8
- # @option opts [false|true] :src_locations
9
- # @option opts [String] :key_filter
10
- # @return [Array<String>]
11
- def used_keys(opts = {})
12
- if opts[:key_filter]
13
- scanner.with_key_filter(opts[:key_filter]) do
14
- return used_keys(opts.except(:key_filter))
15
- end
16
- else
17
- if opts[:src_locations]
18
- used_keys_group scanner.keys_with_src_locations
19
- else
20
- @used_keys ||= used_keys_group scanner.keys
21
- end
8
+ # find all keys in the source (relative keys are absolutized)
9
+ # @option opts [false|true] :source_locations
10
+ # @option opts [String] :key_filter
11
+ # @return [Array<String>]
12
+ def used_tree(opts = {})
13
+ return scanner.with_key_filter(opts[:key_filter]) { used_tree(opts.except(:key_filter)) } if opts[:key_filter]
14
+ key_attrs = opts[:source_locations] ? scanner.keys_with_source_locations : scanner.keys
15
+ Data::Tree::Node.new(
16
+ key: 'used',
17
+ data: {key_filter: scanner.key_filter},
18
+ children: Data::Tree::Siblings.from_key_attr(key_attrs)
19
+ ).to_siblings
22
20
  end
23
- end
24
21
 
25
- def used_keys_group(keys)
26
- ::I18n::Tasks::KeyGroup.new keys, type: :used, key_filter: scanner.key_filter
27
- end
22
+ def scanner
23
+ @scanner ||= begin
24
+ search_config = (config[:search] || {}).with_indifferent_access
25
+ class_name = search_config[:scanner] || '::I18n::Tasks::Scanners::PatternWithScopeScanner'
26
+ class_name.constantize.new search_config.merge(relative_roots: relative_roots)
27
+ end
28
+ end
28
29
 
29
- def scanner
30
- @scanner ||= begin
31
- search_config = (config[:search] || {}).with_indifferent_access
32
- class_name = search_config[:scanner] || '::I18n::Tasks::Scanners::PatternWithScopeScanner'
33
- class_name.constantize.new search_config.merge(relative_roots: relative_roots)
30
+ def used_key_names
31
+ @used_key_names ||= used_tree.key_names
34
32
  end
35
- end
36
33
 
37
- # whether the key is used in the source
38
- def used_key?(key)
39
- used_keys.include?(key)
40
- end
34
+ # whether the key is used in the source
35
+ def used_key?(key)
36
+ used_key_names.include?(key)
37
+ end
41
38
 
42
- # @return whether the key is potentially used in a code expression such as:
43
- # t("category.#{category_key}")
44
- def used_in_expr?(key)
45
- !!(key =~ expr_key_re)
46
- end
39
+ # @return whether the key is potentially used in a code expression such as:
40
+ # t("category.#{category_key}")
41
+ def used_in_expr?(key)
42
+ !!(key =~ expr_key_re)
43
+ end
47
44
 
48
- # keys in the source that end with a ., e.g. t("category.#{cat.i18n_key}") or t("category." + category.key)
49
- def expr_key_re
50
- @expr_key_re ||= compile_key_pattern "{#{used_keys.keys.select(&:expr?).map(&:key_match_pattern) * ','}}"
45
+ # keys in the source that end with a ., e.g. t("category.#{cat.i18n_key}") or t("category." + category.key)
46
+ def expr_key_re
47
+ @expr_key_re ||= begin
48
+ patterns = used_key_names.select { |k| key_expression?(k) }.map { |k| key_match_pattern(k) }
49
+ compile_key_pattern "{#{patterns * ','}}"
50
+ end
51
+ end
51
52
  end
52
53
  end
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
  module I18n
3
3
  module Tasks
4
- VERSION = '0.4.5'
4
+ VERSION = '0.5.0'
5
5
  end
6
6
  end
@@ -27,7 +27,7 @@ describe 'i18n-tasks' do
27
27
  end
28
28
  end
29
29
 
30
- let(:expected_unused_keys) { %w(unused.a unused.numeric unused.plural) }
30
+ let(:expected_unused_keys) { %w(unused.a unused.numeric unused.plural).map { |k| %w(en es).map { |l| "#{l}.#{k}" } }.reduce(:+) }
31
31
  describe 'unused' do
32
32
  it 'detects unused' do
33
33
  capture_stderr do
@@ -40,7 +40,8 @@ describe 'i18n-tasks' do
40
40
  it 'removes unused' do
41
41
  in_test_app_dir do
42
42
  t = i18n_task
43
- expected_unused_keys.each do |key|
43
+ unused = expected_unused_keys.map { |k| k.split('.', 2)[1] }
44
+ unused.each do |key|
44
45
  expect(t.key_value?(key, :en)).to be true
45
46
  expect(t.key_value?(key, :es)).to be true
46
47
  end
@@ -49,7 +50,7 @@ describe 'i18n-tasks' do
49
50
  run_cmd :remove_unused
50
51
  }
51
52
  t.data.reload
52
- expected_unused_keys.each do |key|
53
+ unused.each do |key|
53
54
  expect(t.key_value?(key, :en)).to be false
54
55
  expect(t.key_value?(key, :es)).to be false
55
56
  end
@@ -139,7 +140,7 @@ describe 'i18n-tasks' do
139
140
  used.a 2
140
141
  app/views/usages.html.slim:1 p = t 'used.a'
141
142
  app/views/usages.html.slim:2 b = t 'used.a'
142
- TXT
143
+ TXT
143
144
  end
144
145
  end
145
146
  end
@@ -151,53 +152,53 @@ TXT
151
152
  gen_data = ->(v) {
152
153
  v_num = v.chars.map(&:ord).join('').to_i
153
154
  {
154
- 'ca' => {'a' => v, 'b' => v, 'c' => v, 'd' => v, 'e' => "#{v}%{i}", 'f' => "#{v}%{i}"},
155
- 'cb' => {'a' => v, 'b' => "#{v}%{i}"},
156
- 'hash' => {
157
- 'pattern' => {'a' => v},
158
- 'pattern2' => {'a' => v},
159
- },
160
- 'unused' => {'a' => v, 'numeric' => v_num, 'plural' => {'one' => v, 'other' => v}},
161
- 'ignore_unused' => {'a' => v},
162
- 'missing_in_es' => {'a' => v},
163
- 'missing_in_es_plural_1' => { 'a' => {'one' => v, 'other' => v}},
164
- 'missing_in_es_plural_2' => { 'a' => {'one' => v, 'other' => v}},
165
- 'same_in_es' => {'a' => v},
166
- 'ignore_eq_base_all' => {'a' => v},
167
- 'ignore_eq_base_es' => {'a' => v},
168
- 'blank_in_es' => {'a' => v},
169
- 'relative' => {
170
- 'index' => {
171
- 'title' => v,
172
- 'description' => v,
173
- 'summary' => v,
174
- }
175
- },
176
- 'numeric' => {'a' => v_num},
177
- 'plural' => {'a' => {'one' => v, 'other' => "%{count} #{v}s"}},
178
- 'devise' => {'a' => v},
179
- 'scoped' => {'x' => v},
180
- 'very' => {'scoped' => {'x' => v}},
181
- 'used' => {'a' => v}
155
+ 'ca' => {'a' => v, 'b' => v, 'c' => v, 'd' => v, 'e' => "#{v}%{i}", 'f' => "#{v}%{i}"},
156
+ 'cb' => {'a' => v, 'b' => "#{v}%{i}"},
157
+ 'hash' => {
158
+ 'pattern' => {'a' => v},
159
+ 'pattern2' => {'a' => v},
160
+ },
161
+ 'unused' => {'a' => v, 'numeric' => v_num, 'plural' => {'one' => v, 'other' => v}},
162
+ 'ignore_unused' => {'a' => v},
163
+ 'missing_in_es' => {'a' => v},
164
+ 'missing_in_es_plural_1' => {'a' => {'one' => v, 'other' => v}},
165
+ 'missing_in_es_plural_2' => {'a' => {'one' => v, 'other' => v}},
166
+ 'same_in_es' => {'a' => v},
167
+ 'ignore_eq_base_all' => {'a' => v},
168
+ 'ignore_eq_base_es' => {'a' => v},
169
+ 'blank_in_es' => {'a' => v},
170
+ 'relative' => {
171
+ 'index' => {
172
+ 'title' => v,
173
+ 'description' => v,
174
+ 'summary' => v,
175
+ }
176
+ },
177
+ 'numeric' => {'a' => v_num},
178
+ 'plural' => {'a' => {'one' => v, 'other' => "%{count} #{v}s"}},
179
+ 'devise' => {'a' => v},
180
+ 'scoped' => {'x' => v},
181
+ 'very' => {'scoped' => {'x' => v}},
182
+ 'used' => {'a' => v}
182
183
  }.tap { |r|
183
184
  gen = r["bench"] = {}
184
185
  BENCH_KEYS.times { |i| gen["key#{i}"] = v }
185
186
  }
186
187
  }
187
188
 
188
- en_data = gen_data.('EN_TEXT')
189
- es_data = gen_data.('ES_TEXT').except(
189
+ en_data = gen_data.('EN_TEXT')
190
+ es_data = gen_data.('ES_TEXT').except(
190
191
  'missing_in_es', 'missing_in_es_plural_1', 'missing_in_es_plural_2')
191
- es_data['same_in_es']['a'] = 'EN_TEXT'
192
- es_data['blank_in_es']['a'] = ''
192
+ es_data['same_in_es']['a'] = 'EN_TEXT'
193
+ es_data['blank_in_es']['a'] = ''
193
194
  es_data['ignore_eq_base_all']['a'] = 'EN_TEXT'
194
195
  es_data['ignore_eq_base_es']['a'] = 'EN_TEXT'
195
196
 
196
197
  fs = fixtures_contents.merge(
197
- 'config/locales/en.yml' => {'en' => en_data}.to_yaml,
198
- 'config/locales/es.yml' => {'es' => es_data}.to_yaml,
199
- # test that our algorithms can scale to the order of {BENCH_KEYS} keys.
200
- 'vendor/heavy.file' => BENCH_KEYS.times.map { |i| "t('bench.key#{i}') " }.join
198
+ 'config/locales/en.yml' => {'en' => en_data}.to_yaml,
199
+ 'config/locales/es.yml' => {'es' => es_data}.to_yaml,
200
+ # test that our algorithms can scale to the order of {BENCH_KEYS} keys.
201
+ 'vendor/heavy.file' => BENCH_KEYS.times.map { |i| "t('bench.key#{i}') " }.join
201
202
  )
202
203
 
203
204
  TestCodebase.setup fs
@@ -3,6 +3,18 @@ require 'spec_helper'
3
3
 
4
4
  describe 'Tree siblings / forest' do
5
5
 
6
+ context 'Node' do
7
+ it '::new with children' do
8
+ children = I18n::Tasks::Data::Tree::Siblings.from_key_attr([['a', value: 1]])
9
+ #require 'byebug'; byebug
10
+ node = I18n::Tasks::Data::Tree::Node.new(
11
+ key: 'fr',
12
+ children: children
13
+ )
14
+ expect(node.to_siblings.first.children.first.parent.key).to eq 'fr'
15
+ end
16
+ end
17
+
6
18
  context 'a tree' do
7
19
  let(:a_hash) { {a: 1, b: {ba: 1, bb: 2}}.deep_stringify_keys }
8
20
 
@@ -22,9 +34,22 @@ describe 'Tree siblings / forest' do
22
34
  end
23
35
 
24
36
  it '#merge' do
25
- a = build_tree(a_hash)
37
+ a = build_tree(a_hash)
26
38
  b_hash = {b: {bc: 1}, c: 1}.deep_stringify_keys
27
39
  expect(a.merge(build_tree(b_hash)).to_hash).to eq(a_hash.deep_merge(b_hash))
28
40
  end
41
+
42
+ it '#intersect' do
43
+ x = {a: 1, b: {ba: 1, bb: 2}}
44
+ y = {b: {ba: 1, bc: 3}, c: 1}
45
+ intersection = {b: {ba: 1}}.deep_stringify_keys
46
+ a = build_tree(x)
47
+ b = build_tree(y)
48
+ expect(a.intersect_keys(b, root: true).to_hash).to eq(intersection)
49
+ end
50
+
51
+ it '#select_keys' do
52
+ expect(build_tree(a: 1, b: 1).select_keys {|k, node| k == 'b'}.to_hash).to eq({'b' => 1})
53
+ end
29
54
  end
30
55
  end
@@ -11,9 +11,12 @@ RSpec::Matchers.define :be_i18n_keys do |expected|
11
11
  row.gsub(/(?:\s|^)\|(?:\s|$)/, ' ').gsub(/\s+/, ' ').strip.split(' ').map(&:presence).compact
12
12
  }
13
13
  return [] if actual.empty?
14
- if actual[0][1] =~ /[✗∅=]/
14
+ if actual[0][1] =~ /([✗∅=])/
15
15
  locale_col = 0
16
16
  key_col = 2
17
+ elsif actual[0].length == 3
18
+ locale_col = 0
19
+ key_col = 1
17
20
  else
18
21
  key_col = 0
19
22
  end
@@ -1,6 +1,11 @@
1
1
  # coding: utf-8
2
2
  module Trees
3
+ def expect_node_key_data(node, key, data)
4
+ expect(node.full_key(root: false)).to eq key
5
+ expect(node.data).to eq data
6
+ end
7
+
3
8
  def build_tree(hash)
4
- I18n::Tasks::Data::Tree::Siblings.from_nested_hash(hash)
9
+ I18n::Tasks::Data::Tree::Siblings.from_nested_hash(hash.deep_stringify_keys)
5
10
  end
6
11
  end
@@ -15,26 +15,34 @@ h1 = t 'b'
15
15
  TestCodebase.teardown
16
16
  end
17
17
 
18
- it '#used_keys(src_locations: true)' do
19
- used_keys = task.used_keys(src_locations: true)
20
- expect(used_keys.size).to eq 2
21
- expect(used_keys[0].own_attr).to(
22
- eq(key: 'a',
23
- usages: [{pos: 6, line_num: 1, line_pos: 7, line: "div = t 'a'", path: 'a.html.slim'},
24
- {pos: 18, line_num: 2, line_pos: 7, line: " p = t 'a'", path: 'a.html.slim'}])
18
+ it '#used_keys(source_locations: true)' do
19
+ used = task.used_tree(source_locations: true)
20
+ leaves = used.leaves.to_a
21
+ expect(leaves.size).to eq 2
22
+ expect_node_key_data(
23
+ leaves[0],
24
+ 'a',
25
+ source_locations:
26
+ [{pos: 6, line_num: 1, line_pos: 7, line: "div = t 'a'", path: 'a.html.slim'},
27
+ {pos: 18, line_num: 2, line_pos: 7, line: " p = t 'a'", path: 'a.html.slim'}]
25
28
  )
26
- expect(used_keys[1].own_attr).to(
27
- eq(key: 'b',
28
- usages: [{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", path: 'a.html.slim'}])
29
+
30
+ expect_node_key_data(
31
+ leaves[1],
32
+ 'b',
33
+ source_locations:
34
+ [{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", path: 'a.html.slim'}]
29
35
  )
30
36
  end
31
37
 
32
- it '#used_keys(src_locations: true, key_filter: "b*")' do
33
- used_keys = task.used_keys(key_filter: 'b*', src_locations: true)
38
+ it '#used_keys(source_locations: true, key_filter: "b*")' do
39
+ used_keys = task.used_tree(key_filter: 'b*', source_locations: true)
34
40
  expect(used_keys.size).to eq 1
35
- expect(used_keys[0].own_attr).to(
36
- eq(key: 'b',
37
- usages: [{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", path: 'a.html.slim'}])
41
+ expect_node_key_data(
42
+ used_keys.leaves.first,
43
+ 'b',
44
+ source_locations:
45
+ [{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", path: 'a.html.slim'}]
38
46
  )
39
47
  end
40
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-18 00:00:00.000000000 Z
11
+ date: 2014-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erubis
@@ -180,7 +180,7 @@ dependencies:
180
180
  version: '0'
181
181
  description: |2
182
182
 
183
- i18n-tasks finds and manages missing and unused translations in your application.
183
+ i18n-tasks helps you find and manage missing and unused translations.
184
184
 
185
185
  It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
186
186
  It can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
@@ -210,6 +210,7 @@ files:
210
210
  - lib/i18n/tasks/commands.rb
211
211
  - lib/i18n/tasks/commands_base.rb
212
212
  - lib/i18n/tasks/configuration.rb
213
+ - lib/i18n/tasks/console_context.rb
213
214
  - lib/i18n/tasks/data.rb
214
215
  - lib/i18n/tasks/data/adapter/json_adapter.rb
215
216
  - lib/i18n/tasks/data/adapter/yaml_adapter.rb
@@ -222,15 +223,9 @@ files:
222
223
  - lib/i18n/tasks/data/tree/nodes.rb
223
224
  - lib/i18n/tasks/data/tree/siblings.rb
224
225
  - lib/i18n/tasks/data/tree/traversal.rb
225
- - lib/i18n/tasks/file_structure.rb
226
226
  - lib/i18n/tasks/fill_tasks.rb
227
227
  - lib/i18n/tasks/google_translation.rb
228
228
  - lib/i18n/tasks/ignore_keys.rb
229
- - lib/i18n/tasks/key.rb
230
- - lib/i18n/tasks/key/key_group.rb
231
- - lib/i18n/tasks/key/match_pattern.rb
232
- - lib/i18n/tasks/key/usages.rb
233
- - lib/i18n/tasks/key_group.rb
234
229
  - lib/i18n/tasks/key_pattern_matching.rb
235
230
  - lib/i18n/tasks/logging.rb
236
231
  - lib/i18n/tasks/missing_keys.rb
@@ -255,7 +250,6 @@ files:
255
250
  - spec/fixtures/config/i18n-tasks.yml
256
251
  - spec/google_translate_spec.rb
257
252
  - spec/i18n_tasks_spec.rb
258
- - spec/key_group_spec.rb
259
253
  - spec/key_pattern_matching_spec.rb
260
254
  - spec/locale_tree/siblings_spec.rb
261
255
  - spec/pattern_scanner_spec.rb
@@ -307,7 +301,6 @@ test_files:
307
301
  - spec/fixtures/config/i18n-tasks.yml
308
302
  - spec/google_translate_spec.rb
309
303
  - spec/i18n_tasks_spec.rb
310
- - spec/key_group_spec.rb
311
304
  - spec/key_pattern_matching_spec.rb
312
305
  - spec/locale_tree/siblings_spec.rb
313
306
  - spec/pattern_scanner_spec.rb
@@ -1,19 +0,0 @@
1
- # coding: utf-8
2
- module I18n::Tasks::FileStructure
3
- def identify(routes = data.config.read)
4
-
5
- end
6
-
7
-
8
- class NonLeafVisitor
9
- def visit(node)
10
- puts "non-leaf: #{node}"
11
- end
12
- end
13
-
14
- class LeafVisitor
15
- def visit(node)
16
- puts "leaf: #{node}"
17
- end
18
- end
19
- end
@@ -1,48 +0,0 @@
1
- # coding: utf-8
2
- require 'i18n/tasks/key/key_group'
3
- require 'i18n/tasks/key/match_pattern'
4
- require 'i18n/tasks/key/usages'
5
-
6
- module I18n
7
- module Tasks
8
- # Container for i18n key and its attributes
9
- class Key
10
- include ::I18n::Tasks::Key::KeyGroup
11
- include ::I18n::Tasks::Key::MatchPattern
12
- include ::I18n::Tasks::Key::Usages
13
-
14
- attr_accessor :own_attr
15
-
16
- # @param [Array<Key, Value>|Hash|String] key_or_attr
17
- # @param [Hash] attr optional
18
- def initialize(key_or_attr, own_attr = {})
19
- @own_attr = if key_or_attr.is_a?(Array)
20
- {key: key_or_attr[0], value: key_or_attr[1]}.merge(own_attr)
21
- elsif key_or_attr.is_a?(Hash)
22
- key_or_attr.merge(own_attr)
23
- else
24
- (own_attr || {}).merge(key: key_or_attr)
25
- end
26
- @own_attr[:key] = @own_attr[:key].to_s
27
- end
28
-
29
- def ==(other)
30
- self.attr == other.attr
31
- end
32
-
33
- def inspect
34
- "#<#{self.class.name}#{attr.inspect}>"
35
- end
36
-
37
- def key
38
- @own_attr[:key]
39
- end
40
-
41
- alias to_s key
42
-
43
- def value
44
- @own_attr[:value]
45
- end
46
- end
47
- end
48
- end