i18n-tasks 0.4.5 → 0.5.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.
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