thinreports 0.6.0.pre3

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 (146) hide show
  1. data/.yardopts +1 -0
  2. data/README.rdoc +100 -0
  3. data/Rakefile +10 -0
  4. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  5. data/lib/thinreports.rb +11 -0
  6. data/lib/thinreports/core.rb +20 -0
  7. data/lib/thinreports/core/errors.rb +58 -0
  8. data/lib/thinreports/core/events.rb +71 -0
  9. data/lib/thinreports/core/ext.rb +5 -0
  10. data/lib/thinreports/core/ext/array.rb +19 -0
  11. data/lib/thinreports/core/ext/hash.rb +19 -0
  12. data/lib/thinreports/core/ext/object.rb +25 -0
  13. data/lib/thinreports/core/format.rb +14 -0
  14. data/lib/thinreports/core/format/base.rb +93 -0
  15. data/lib/thinreports/core/format/builder.rb +65 -0
  16. data/lib/thinreports/core/ordered_hash.rb +39 -0
  17. data/lib/thinreports/core/page.rb +91 -0
  18. data/lib/thinreports/core/shape.rb +53 -0
  19. data/lib/thinreports/core/shape/base.rb +16 -0
  20. data/lib/thinreports/core/shape/base/interface.rb +38 -0
  21. data/lib/thinreports/core/shape/base/internal.rb +60 -0
  22. data/lib/thinreports/core/shape/basic.rb +15 -0
  23. data/lib/thinreports/core/shape/basic/format.rb +26 -0
  24. data/lib/thinreports/core/shape/basic/interface.rb +57 -0
  25. data/lib/thinreports/core/shape/basic/internal.rb +29 -0
  26. data/lib/thinreports/core/shape/list.rb +25 -0
  27. data/lib/thinreports/core/shape/list/configuration.rb +33 -0
  28. data/lib/thinreports/core/shape/list/events.rb +30 -0
  29. data/lib/thinreports/core/shape/list/format.rb +72 -0
  30. data/lib/thinreports/core/shape/list/manager.rb +209 -0
  31. data/lib/thinreports/core/shape/list/page.rb +118 -0
  32. data/lib/thinreports/core/shape/list/page_state.rb +40 -0
  33. data/lib/thinreports/core/shape/list/section_format.rb +32 -0
  34. data/lib/thinreports/core/shape/list/section_interface.rb +48 -0
  35. data/lib/thinreports/core/shape/list/section_internal.rb +29 -0
  36. data/lib/thinreports/core/shape/list/store.rb +34 -0
  37. data/lib/thinreports/core/shape/manager.rb +14 -0
  38. data/lib/thinreports/core/shape/manager/format.rb +28 -0
  39. data/lib/thinreports/core/shape/manager/internal.rb +87 -0
  40. data/lib/thinreports/core/shape/manager/target.rb +85 -0
  41. data/lib/thinreports/core/shape/tblock.rb +16 -0
  42. data/lib/thinreports/core/shape/tblock/format.rb +36 -0
  43. data/lib/thinreports/core/shape/tblock/formatter.rb +32 -0
  44. data/lib/thinreports/core/shape/tblock/formatter/basic.rb +38 -0
  45. data/lib/thinreports/core/shape/tblock/formatter/datetime.rb +21 -0
  46. data/lib/thinreports/core/shape/tblock/formatter/number.rb +49 -0
  47. data/lib/thinreports/core/shape/tblock/formatter/padding.rb +43 -0
  48. data/lib/thinreports/core/shape/tblock/interface.rb +52 -0
  49. data/lib/thinreports/core/shape/tblock/internal.rb +70 -0
  50. data/lib/thinreports/core/shape/text.rb +15 -0
  51. data/lib/thinreports/core/shape/text/format.rb +25 -0
  52. data/lib/thinreports/core/shape/text/interface.rb +16 -0
  53. data/lib/thinreports/core/shape/text/internal.rb +17 -0
  54. data/lib/thinreports/core/utils.rb +48 -0
  55. data/lib/thinreports/generator.rb +30 -0
  56. data/lib/thinreports/generator/base.rb +49 -0
  57. data/lib/thinreports/generator/pdf.rb +63 -0
  58. data/lib/thinreports/generator/pdf/document.rb +171 -0
  59. data/lib/thinreports/generator/pdf/document/draw_shape.rb +74 -0
  60. data/lib/thinreports/generator/pdf/document/font.rb +59 -0
  61. data/lib/thinreports/generator/pdf/document/graphics.rb +42 -0
  62. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +92 -0
  63. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +132 -0
  64. data/lib/thinreports/generator/pdf/document/graphics/image.rb +51 -0
  65. data/lib/thinreports/generator/pdf/document/graphics/text.rb +130 -0
  66. data/lib/thinreports/generator/pdf/document/parse_color.rb +51 -0
  67. data/lib/thinreports/generator/pdf/document/parse_svg.rb +102 -0
  68. data/lib/thinreports/generator/pdf/drawer.rb +16 -0
  69. data/lib/thinreports/generator/pdf/drawer/base.rb +56 -0
  70. data/lib/thinreports/generator/pdf/drawer/list.rb +39 -0
  71. data/lib/thinreports/generator/pdf/drawer/list_section.rb +46 -0
  72. data/lib/thinreports/generator/pdf/drawer/page.rb +101 -0
  73. data/lib/thinreports/generator/pdf/prawn_ext.rb +36 -0
  74. data/lib/thinreports/generator/pxd.rb +75 -0
  75. data/lib/thinreports/generator/pxd/helper.rb +33 -0
  76. data/lib/thinreports/generator/pxd/list_renderer.rb +58 -0
  77. data/lib/thinreports/generator/pxd/page_renderer.rb +75 -0
  78. data/lib/thinreports/layout.rb +17 -0
  79. data/lib/thinreports/layout/base.rb +78 -0
  80. data/lib/thinreports/layout/configuration.rb +27 -0
  81. data/lib/thinreports/layout/format.rb +77 -0
  82. data/lib/thinreports/layout/version.rb +43 -0
  83. data/lib/thinreports/report.rb +31 -0
  84. data/lib/thinreports/report/base.rb +160 -0
  85. data/lib/thinreports/report/events.rb +32 -0
  86. data/lib/thinreports/report/internal.rb +131 -0
  87. data/resources/fonts/IPA_Font_License_Agreement_v1.0.txt +117 -0
  88. data/resources/fonts/ipag.ttf +0 -0
  89. data/resources/fonts/ipagp.ttf +0 -0
  90. data/resources/fonts/ipam.ttf +0 -0
  91. data/resources/fonts/ipamp.ttf +0 -0
  92. data/tasks/clean.rake +6 -0
  93. data/tasks/doc.rake +13 -0
  94. data/tasks/test.rake +18 -0
  95. data/test/unit/core/ext/array_spec.rb +29 -0
  96. data/test/unit/core/ext/hash_spec.rb +29 -0
  97. data/test/unit/core/ext/object_spec.rb +30 -0
  98. data/test/unit/core/format/test_base.rb +148 -0
  99. data/test/unit/core/format/test_builder.rb +114 -0
  100. data/test/unit/core/ordered_hash_spec.rb +51 -0
  101. data/test/unit/core/shape/base/test_interface.rb +52 -0
  102. data/test/unit/core/shape/base/test_internal.rb +109 -0
  103. data/test/unit/core/shape/basic/test_format.rb +59 -0
  104. data/test/unit/core/shape/basic/test_interface.rb +70 -0
  105. data/test/unit/core/shape/basic/test_internal.rb +42 -0
  106. data/test/unit/core/shape/list/test_configuration.rb +52 -0
  107. data/test/unit/core/shape/list/test_events.rb +28 -0
  108. data/test/unit/core/shape/list/test_format.rb +71 -0
  109. data/test/unit/core/shape/list/test_page.rb +10 -0
  110. data/test/unit/core/shape/list/test_page_state.rb +31 -0
  111. data/test/unit/core/shape/list/test_section_format.rb +46 -0
  112. data/test/unit/core/shape/list/test_section_interface.rb +52 -0
  113. data/test/unit/core/shape/list/test_section_internal.rb +30 -0
  114. data/test/unit/core/shape/list/test_store.rb +41 -0
  115. data/test/unit/core/shape/manager/test_format.rb +40 -0
  116. data/test/unit/core/shape/manager/test_internal.rb +137 -0
  117. data/test/unit/core/shape/manager/test_target.rb +109 -0
  118. data/test/unit/core/shape/tblock/formatter/test_basic.rb +24 -0
  119. data/test/unit/core/shape/tblock/formatter/test_datetime.rb +47 -0
  120. data/test/unit/core/shape/tblock/formatter/test_number.rb +76 -0
  121. data/test/unit/core/shape/tblock/formatter/test_padding.rb +72 -0
  122. data/test/unit/core/shape/tblock/test_format.rb +125 -0
  123. data/test/unit/core/shape/tblock/test_formatter.rb +28 -0
  124. data/test/unit/core/shape/tblock/test_interface.rb +40 -0
  125. data/test/unit/core/shape/tblock/test_internal.rb +139 -0
  126. data/test/unit/core/shape/text/test_format.rb +73 -0
  127. data/test/unit/core/shape/text/test_internal.rb +21 -0
  128. data/test/unit/core/test_events.rb +91 -0
  129. data/test/unit/core/test_shape.rb +35 -0
  130. data/test/unit/core/utils_spec.rb +56 -0
  131. data/test/unit/generator/pdf/document/graphics/test_attributes.rb +103 -0
  132. data/test/unit/generator/pdf/document/test_font.rb +54 -0
  133. data/test/unit/generator/pdf/document/test_graphics.rb +43 -0
  134. data/test/unit/generator/pdf/document/test_parse_color.rb +30 -0
  135. data/test/unit/generator/test_base.rb +51 -0
  136. data/test/unit/helper.rb +37 -0
  137. data/test/unit/layout/test_base.rb +92 -0
  138. data/test/unit/layout/test_configuration.rb +46 -0
  139. data/test/unit/layout/test_format.rb +104 -0
  140. data/test/unit/layout/test_version.rb +62 -0
  141. data/test/unit/report/test_base.rb +187 -0
  142. data/test/unit/report/test_events.rb +22 -0
  143. data/test/unit/report/test_internal.rb +234 -0
  144. data/test/unit/test_layout.rb +12 -0
  145. data/test/unit/test_report.rb +30 -0
  146. metadata +218 -0
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
data/README.rdoc ADDED
@@ -0,0 +1,100 @@
1
+ = ThinReports Generator
2
+
3
+ ThinReports is Open Source Reporting Solution for Ruby.
4
+ And it provide you these tools.
5
+
6
+ * ThinReports Editor (GUI Layout Editor)
7
+ * ThinReports Generator (Report Generation Interface for Ruby)
8
+
9
+ Please refer to {Official Site}[http://www.thinreports.org/] and
10
+ {Project Site}[http://osc.matsukei.net/projects/thinreports/wiki] for more details.
11
+
12
+ == Quick Start
13
+
14
+ Getting started with ThinReports Generator can be as simple as:
15
+
16
+ require 'thinreports'
17
+
18
+ report = ThinReports::Report.new :layout => 'report.tlf'
19
+ report.start_new_page do
20
+ page.item(:title).value('ThinReports')
21
+ end
22
+
23
+ report.generate_file(:pdf, 'report.pdf')
24
+
25
+ Or can be as:
26
+
27
+ ThinReports::Report.generate_file(:pdf, 'report.pdf', :layout => 'report.tlf') do
28
+ start_new_page
29
+
30
+ page.item(:title).value('ThinReports')
31
+
32
+ start_new_page
33
+
34
+ page.item(:title).value('ThinReports').style(:fill, 'red')
35
+ end
36
+
37
+ {Learn more}[http://osc.matsukei.net/projects/thinreports/wiki/Getting_Started].
38
+
39
+ == Documentation
40
+
41
+ We provide you a few useful resources to help you get started with ThinReports.
42
+
43
+ * {Getting Started}[http://osc.matsukei.net/projects/thinreports/wiki/Getting_Started]
44
+ * {Guide}[http://osc.matsukei.net/projects/thinreports/wiki/Guide]
45
+ * {Roadmap}[http://osc.matsukei.net/projects/thinreports/roadmap]
46
+ * {Changelog}[http://osc.matsukei.net/projects/thinreports/wiki/Changelog]
47
+
48
+ == Source Code
49
+
50
+ Please see {here}[http://osc.matsukei.net/projects/thinreports/wiki/Source_Code].
51
+
52
+ == Community Support
53
+
54
+ * {Open Forum}[http://osc.matsukei.net/projects/thinreports/boards]
55
+ * {Issue Tracker (Read-Only)}[http://osc.matsukei.net/projects/thinreports/issues]
56
+
57
+ == Dependencies
58
+
59
+ * <code>prawn</code> <code>= 0.11.1</code>
60
+ * <code>json</code> <code>>= 1.4.6</code>
61
+ (Only for less than Ruby 1.9)
62
+
63
+ === Note
64
+
65
+ We tested on <code>Ruby 1.8.7</code> and <code>1.9.2</code>.
66
+ We recommend <code>1.9.2+</code>.
67
+
68
+ == Resources
69
+
70
+ === Fonts
71
+
72
+ ThinReports includes the following fonts.
73
+
74
+ * IPAFonts: Copyright(c) 2003-2011 Information-technology Promotion Agency, Japan.
75
+ Please see the lincense file {IPA_Font_License_Agreement_v1.0.txt}[http://ipafont.ipa.go.jp/ipa_font_license_v1.html].
76
+
77
+ == License
78
+
79
+ (The MIT License)
80
+
81
+ Copyright (c) 2010-2011 Matsukei Co.,Ltd.
82
+
83
+ Permission is hereby granted, free of charge, to any person obtaining
84
+ a copy of this software and associated documentation files (the
85
+ 'Software'), to deal in the Software without restriction, including
86
+ without limitation the rights to use, copy, modify, merge, publish,
87
+ distribute, sublicense, and/or sell copies of the Software, and to
88
+ permit persons to whom the Software is furnished to do so, subject to
89
+ the following conditions:
90
+
91
+ The above copyright notice and this permission notice shall be
92
+ included in all copies or substantial portions of the Software.
93
+
94
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
95
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
96
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
97
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
98
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
99
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
100
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # coding: utf-8
2
+
3
+ # Load thinreports
4
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/lib'))
5
+ require 'thinreports'
6
+
7
+ # Load tasks
8
+ Dir.glob('tasks/**/*.rake').each do |r|
9
+ Rake.application.add_import r
10
+ end
@@ -0,0 +1,10 @@
1
+ <script type="text/javascript">
2
+ var _gaq = _gaq || [];
3
+ _gaq.push(['_setAccount', 'UA-19321975-2']);
4
+ _gaq.push(['_trackPageview']);
5
+ (function() {
6
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
7
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
8
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
9
+ })();
10
+ </script>
@@ -0,0 +1,11 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ # The current version.
5
+ VERSION = '0.6.0.pre3'
6
+ end
7
+
8
+ require 'thinreports/core'
9
+ require 'thinreports/report'
10
+ require 'thinreports/layout'
11
+ require 'thinreports/generator'
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+
5
+ ROOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
6
+
7
+ module Core
8
+ end
9
+
10
+ end
11
+
12
+ require 'thinreports/core/ext'
13
+ require 'thinreports/core/utils'
14
+ require 'thinreports/core/ordered_hash'
15
+
16
+ require 'thinreports/core/errors'
17
+ require 'thinreports/core/events'
18
+ require 'thinreports/core/format'
19
+ require 'thinreports/core/shape'
20
+ require 'thinreports/core/page'
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+
5
+ module Errors
6
+ class Basic < ::StandardError
7
+ end
8
+
9
+ class UnknownShapeStyleName < Basic
10
+ end
11
+
12
+ class UnknownShapeType < Basic
13
+ end
14
+
15
+ class UnknownFormatterType < Basic
16
+ end
17
+
18
+ class LayoutFileNotFound < Basic
19
+ end
20
+
21
+ class NoRegisteredLayoutFound < Basic
22
+ end
23
+
24
+ class UnknownItemId < Basic
25
+ end
26
+
27
+ class DisabledListSection < Basic
28
+ end
29
+
30
+ class UnknownEventType < Basic
31
+ end
32
+
33
+ class UnknownLayoutId < Basic
34
+ end
35
+
36
+ class UnknownGeneratorType < Basic
37
+ end
38
+
39
+ class NoConfigurationFound < Basic
40
+ end
41
+
42
+ class UnsupportedColorName < Basic
43
+ end
44
+
45
+ class InvalidLayoutFormat < Basic
46
+ end
47
+
48
+ class IncompatibleLayoutFormat < Basic
49
+ def initialize(filename, fileversion, required_rules)
50
+ super("Generator #{ThinReports::VERSION} can not be built this file, " +
51
+ "'#{File.basename(filename)}'." +
52
+ "This file is created in the Editor of version '#{fileversion}', " +
53
+ "but Generator requires version #{required_rules}.")
54
+ end
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,71 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core
5
+
6
+ class Events
7
+ Event = ::Struct.new(:type, :target)
8
+
9
+ # @return [Hash<Symbol, ThinReports::Core::Events::Event>]
10
+ # @private
11
+ attr_accessor :events
12
+
13
+ # @param [Symbol] types
14
+ def initialize(*types)
15
+ @events = {}
16
+ @types = types
17
+ end
18
+
19
+ # @param [Symbol] type
20
+ # @yield [e]
21
+ # @yieldparam [ThinReports::Core::Events::Event] e
22
+ def listen(type, &block)
23
+ verify_event_type(type)
24
+
25
+ if block_given?
26
+ events[type] = block
27
+ else
28
+ raise ArgumentError, '#listen requires a block'
29
+ end
30
+ end
31
+ alias_method :on, :listen
32
+
33
+ # @param [Symbol] type
34
+ def unlisten(type)
35
+ events.delete(type)
36
+ end
37
+ alias_method :un, :unlisten
38
+
39
+ # @private
40
+ def dispatch(e)
41
+ unless e.type
42
+ raise ArgumentError, 'Event#type attribute is required'
43
+ end
44
+ verify_event_type(e.type)
45
+
46
+ if event = events[e.type]
47
+ event.call(e)
48
+ end
49
+ end
50
+
51
+ # @private
52
+ def copy
53
+ new_events = self.dup
54
+ new_events.events = events.simple_deep_copy
55
+ new_events
56
+ end
57
+
58
+ private
59
+
60
+ # @param [Symbol] type
61
+ def verify_event_type(type)
62
+ return if @types.empty?
63
+
64
+ unless @types.include?(type)
65
+ raise ThinReports::Errors::UnknownEventType
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+
3
+ require 'thinreports/core/ext/object'
4
+ require 'thinreports/core/ext/array'
5
+ require 'thinreports/core/ext/hash'
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core
5
+
6
+ # @private
7
+ module ArrayExtensions
8
+ def simple_deep_copy
9
+ map {|v| v.dup rescue v }
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+
16
+ # @private
17
+ class Array
18
+ include ThinReports::Core::ArrayExtensions
19
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core
5
+
6
+ # @private
7
+ module HashExtensions
8
+ def simple_deep_copy
9
+ inject({}) {|h, (k, v)| h[k] = (v.dup rescue v); h}
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+
16
+ # @private
17
+ class Hash
18
+ include ThinReports::Core::HashExtensions
19
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core
5
+
6
+ # @private
7
+ module ObjectExtensions
8
+ unless ::Object.method_defined?(:blank?)
9
+ def blank?
10
+ case self
11
+ when String then self.nil? || self.empty?
12
+ when NilClass then true
13
+ else false
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+
22
+ # @private
23
+ class Object
24
+ include ThinReports::Core::ObjectExtensions
25
+ end
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core
5
+
6
+ # @private
7
+ module Format
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+ require 'thinreports/core/format/builder'
14
+ require 'thinreports/core/format/base'
@@ -0,0 +1,93 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Core::Format
5
+
6
+ # @abstract
7
+ # @private
8
+ class Base
9
+ # Work like a BlankSlate.
10
+ instance_methods.each do |m|
11
+ undef_method(m) unless m.to_s =~ /^(object|eq|__|instance_|=|!)/
12
+ end
13
+
14
+ class << self
15
+ include Core::Format::Builder
16
+
17
+ def config_reader(*configs, &block)
18
+ each_configs(*configs) do |m, location|
19
+ define_read_method(m, location, &block)
20
+ end
21
+ end
22
+
23
+ def config_checker(check, *configs)
24
+ checker = lambda {|val| val == check}
25
+ each_configs(*configs) do |m, location|
26
+ define_read_method(:"#{m}?", location, &checker)
27
+ end
28
+ end
29
+
30
+ def config_writer(*configs)
31
+ each_configs(*configs) do |m, location|
32
+ define_write_method(m, location)
33
+ end
34
+ end
35
+
36
+ def config_accessor(*configs, &block)
37
+ config_reader(*configs, &block)
38
+ config_writer(*configs)
39
+ end
40
+
41
+ private
42
+
43
+ def define_read_method(m, location = nil, &block)
44
+ define_method(m) do
45
+ read(*location, &block)
46
+ end
47
+ end
48
+
49
+ def define_write_method(m, location = nil)
50
+ define_method(:"#{m}=") do |value|
51
+ write(value, *location)
52
+ end
53
+ end
54
+
55
+ def each_configs(*configs, &block)
56
+ c = configs.first.is_a?(::Hash) ? configs.first : (configs || [])
57
+ c.each do |m, location|
58
+ block.call(m, location || [m.to_s])
59
+ end
60
+ end
61
+ end
62
+
63
+ def initialize(config, &block)
64
+ @config = config
65
+ block.call(self) if ::Kernel.block_given?
66
+ end
67
+
68
+ private
69
+
70
+ def find(*keys)
71
+ if keys.empty?
72
+ @config
73
+ else
74
+ keys.inject(@config) do |c, k|
75
+ c.is_a?(::Hash) ? c[k] : (break c)
76
+ end
77
+ end
78
+ end
79
+
80
+ def write(value, *keys)
81
+ key = keys.pop
82
+ owner = find(*keys)
83
+ owner[key] = value
84
+ end
85
+
86
+ def read(*keys, &block)
87
+ value = find(*keys)
88
+ ::Kernel.block_given? ? block.call(value) : value
89
+ end
90
+ end
91
+
92
+ end
93
+ end