thinreports 0.6.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,75 @@
1
+ # coding: utf-8
2
+
3
+ require 'stringio'
4
+ require 'tempfile'
5
+
6
+ module ThinReports
7
+ module Generator
8
+
9
+ class Pxd < Base
10
+ require 'thinreports/generator/pxd/helper'
11
+
12
+ autoload :PageRenderer, 'thinreports/generator/pxd/page_renderer'
13
+ autoload :ListRenderer, 'thinreports/generator/pxd/list_renderer'
14
+
15
+ include Helper
16
+
17
+ # @param report (see ThinReports::Generator::Base#initialize)
18
+ # @param [Hash] options See http://www.pxdoc.com/tech/wiki.cgi?page=pxd
19
+ def initialize(report, options)
20
+ super
21
+ @renderers = {}
22
+ end
23
+
24
+ # @see ThinReports::Generator::Base#generate
25
+ def generate
26
+ output = StringIO.new('', 'r+:UTF-8')
27
+ render_start_pxd(output)
28
+
29
+ report.pages.each do |page|
30
+ render_page(output, page)
31
+ end
32
+
33
+ render_end_pxd(output)
34
+ output.string
35
+ end
36
+
37
+ # @see ThinReports::Generator::Base#generate_file
38
+ def generate_file(filename)
39
+ File.open(filename, 'w') {|f| f << generate }
40
+ end
41
+
42
+ private
43
+
44
+ def renderer(page)
45
+ @renderers[page.layout.format.identifier] ||=
46
+ PageRenderer.new(page.layout.format)
47
+ end
48
+
49
+ def render_page(output, page)
50
+ output << unless page.blank?
51
+ content_tag(:page, renderer(page).render(page.manager), nil,
52
+ :escape => false)
53
+ else
54
+ tag(:page)
55
+ end
56
+ end
57
+
58
+ def render_start_pxd(output)
59
+ format = default_layout.format
60
+ attrs = @options.merge('title' => format.report_title,
61
+ 'paper-type' => format.page_paper_type,
62
+ 'orientation' => format.page_orientation,
63
+ 'width' => format.page_width,
64
+ 'height' => format.page_height,
65
+ 'dpi' => '72')
66
+ output << tag(:pxd, attrs, true)
67
+ end
68
+
69
+ def render_end_pxd(output)
70
+ output << '</pxd>'
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+
3
+ require 'erb'
4
+
5
+ module ThinReports
6
+ module Generator
7
+
8
+ # @private
9
+ module Pxd::Helper
10
+ private
11
+
12
+ def content_tag(tag_name, content = nil, attrs = nil, options = {})
13
+ content = h(content) unless options[:escape] == false
14
+ tag(tag_name, attrs, true) << content.to_s << "</#{h(tag_name)}>"
15
+ end
16
+
17
+ def tag(tag_name, attrs = nil, open = false)
18
+ attrs = tag_attributes(attrs)
19
+ attrs = ' ' + attrs unless attrs.blank?
20
+ "<#{h(tag_name)}#{attrs}#{open ? '' : ' /'}>"
21
+ end
22
+
23
+ def tag_attributes(attrs)
24
+ attrs && attrs.map{|k, v| "#{h(k)}=\"#{h(v)}\"" }.join(' ')
25
+ end
26
+
27
+ def h(s)
28
+ ERB::Util.html_escape(s)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Generator
5
+
6
+ # @private
7
+ class Pxd::ListRenderer
8
+ include Pxd::Helper
9
+
10
+ def initialize
11
+ @renderers = {}
12
+ @list = nil
13
+ end
14
+
15
+ # @param [ThinReports::Core::Shape::List::PageState] list
16
+ def render(list)
17
+ @list = list
18
+
19
+ result = String.new
20
+ render_section(result, list.header) if list.header
21
+
22
+ list.rows.each do |row|
23
+ render_section(result, row)
24
+ end
25
+ result
26
+ end
27
+
28
+ private
29
+
30
+ # @param [String] result
31
+ # @param [ThinReports::Core::Shape::List::SectionInterface] section
32
+ def render_section(result, section)
33
+ internal = section.internal
34
+ attributes = internal.attributes
35
+ contents = renderer(internal.section_name).render(section.manager)
36
+
37
+ # Only for when older than Ver 0.6.0.pre2.
38
+ # Since 0.6.0.pre3, ignore this.
39
+ if internal.relative_top
40
+ attributes['transform'] =
41
+ "translate(#{internal.relative_position.join(',')})"
42
+ end
43
+
44
+ result << content_tag(internal.svg_tag, contents, attributes,
45
+ :escape => false)
46
+ end
47
+
48
+ # @param [Symbol] section_name
49
+ # @return [ThinReports::Generator::Pxd::PageRenderer]
50
+ def renderer(section_name)
51
+ @renderers[section_name] ||=
52
+ Pxd::PageRenderer.new(@list.format.sections[section_name])
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,75 @@
1
+ # coding: utf-8
2
+
3
+ require 'erb'
4
+
5
+ module ThinReports
6
+ module Generator
7
+
8
+ # @private
9
+ class Pxd::PageRenderer
10
+ include Pxd::Helper
11
+
12
+ def initialize(format)
13
+ @engine = ERB.new(read_layout(format))
14
+ @manager = {}
15
+ @lists = {}
16
+ end
17
+
18
+ # @param [ThinReports::Core::Shape::Manager::Internal] manager
19
+ # @return [String]
20
+ def render(manager)
21
+ @manager = manager
22
+ @engine.result(binding)
23
+ end
24
+
25
+ def render_shape(id)
26
+ return '' unless shape = @manager.final_shape(id)
27
+
28
+ shape = shape.internal
29
+ case
30
+ when shape.type_of?(:tblock)
31
+ render_tblock(shape)
32
+ when shape.type_of?(:list)
33
+ render_list(shape)
34
+ when shape.type_of?(:text)
35
+ render_text(shape)
36
+ else
37
+ render_basic(shape)
38
+ end
39
+ end
40
+ alias_method :r, :render_shape
41
+
42
+ private
43
+
44
+ def render_basic(shape)
45
+ tag(shape.svg_tag, shape.attributes)
46
+ end
47
+
48
+ def render_text(shape)
49
+ content_tag(shape.svg_tag, shape.svg_content,
50
+ shape.attribute, :escape => false)
51
+ end
52
+
53
+ def render_tblock(shape)
54
+ value = h(shape.real_value)
55
+ value = if shape.multiple?
56
+ value.gsub(/\r\n|\n/, '<tBreak/>')
57
+ else
58
+ value.gsub(/\r\n|\n/, ' ')
59
+ end
60
+ content_tag(shape.svg_tag, value, shape.attributes, :escape => false)
61
+ end
62
+
63
+ def render_list(shape)
64
+ renderer = @lists[shape.id] ||= Pxd::ListRenderer.new
65
+ renderer.render(shape)
66
+ end
67
+
68
+ def read_layout(format)
69
+ format.layout.gsub(/ x\-[a-z\d\-]+?=".*?"/, '').
70
+ gsub(/ class=".*?"/, '')
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+
5
+ module Layout
6
+ # @see ThinReports::Layout::Base#initialize
7
+ def self.new(filename, options = {})
8
+ Base.new(filename, options)
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ require 'thinreports/layout/version'
15
+ require 'thinreports/layout/base'
16
+ require 'thinreports/layout/format'
17
+ require 'thinreports/layout/configuration'
@@ -0,0 +1,78 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Layout
5
+
6
+ class Base
7
+ EXT_NAME = 'tlf'
8
+
9
+ class << self
10
+ # @param [String] filename
11
+ # @return [ThinReports::Layout::Format]
12
+ # @raise [ThinReports::Errors::InvalidLayoutFormat]
13
+ # @raise [ThinReports::Errors::IncompatibleLayoutFormat]
14
+ # @private
15
+ def load_format(filename)
16
+ filename += ".#{EXT_NAME}" unless filename =~/\.#{EXT_NAME}$/
17
+
18
+ unless File.exists?(filename)
19
+ raise ThinReports::Errors::LayoutFileNotFound
20
+ end
21
+ # Build format.
22
+ ThinReports::Layout::Format.build(filename)
23
+ end
24
+
25
+ # @private
26
+ def Page
27
+ const_defined?(:Page) ? Page : Core::Page
28
+ end
29
+
30
+ private
31
+
32
+ # @private
33
+ def PageHelpers(&block)
34
+ const_set(:Page, ::Class.new(Core::Page, &block))
35
+ end
36
+ end
37
+
38
+ # @private
39
+ attr_reader :format
40
+
41
+ # @return [String]
42
+ attr_reader :filename
43
+
44
+ # @return [Symbol]
45
+ attr_reader :id
46
+
47
+ # @param [String] filename
48
+ # @param [Hash] options
49
+ # @option options [Symbol] :id (nil)
50
+ def initialize(filename, options = {})
51
+ @filename = filename
52
+ @format = self.class.load_format(filename)
53
+ @id = options[:id]
54
+ end
55
+
56
+ # @return [Boolean] Return the true if is default layout.
57
+ def default?
58
+ @id.nil?
59
+ end
60
+
61
+ # @yield [config]
62
+ # @yieldparam [List::Configuration] config
63
+ # @return [List::Configuration]
64
+ def config(&block)
65
+ @config ||= Layout::Configuration.new(self)
66
+ block_exec_on(@config, &block)
67
+ end
68
+
69
+ # @param [ThinReports::Report::Base] parent
70
+ # @return [Page]
71
+ # @private
72
+ def init_new_page(parent)
73
+ self.class.Page.new(parent, self)
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Layout
5
+
6
+ class Configuration
7
+ include Core::Shape::Manager::Target
8
+
9
+ undef_method :items, :values
10
+
11
+ # @param [ThinReports::Layout::Base]
12
+ def initialize(layout)
13
+ initialize_manager(layout.format) do |f|
14
+ Core::Shape::Configuration(f.type).new
15
+ end
16
+ end
17
+
18
+ # @param [String, Symbol] shape_id
19
+ # @return [Object, nil]
20
+ # @private
21
+ def activate(shape_id)
22
+ (config = manager.shapes[shape_id.to_sym]) && config.copy
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,77 @@
1
+ # coding: utf-8
2
+
3
+ require 'digest/sha1'
4
+
5
+ module ThinReports
6
+ module Layout
7
+
8
+ # @private
9
+ class Format < Core::Shape::Manager::Format
10
+ config_reader :last_version => %w( version )
11
+ config_reader :report_title => %w( title )
12
+ config_reader :page_paper_type => %w( config page paper-type ),
13
+ :page_width => %w( config page width ),
14
+ :page_height => %w( config page height ),
15
+ :page_orientation => %w( config page orientation ),
16
+ :page_margin_top => %w( config page margin-top ),
17
+ :page_margin_bottom => %w( config page margin-bottom ),
18
+ :page_margin_left => %w( config page margin-left ),
19
+ :page_margin_left => %w( config page margin-right )
20
+
21
+ config_checker 'user', :user_paper_type => %w( config page paper-type )
22
+
23
+ class << self
24
+
25
+ private
26
+
27
+ # @param [String] filename
28
+ # @param [Hash] options
29
+ # @option options [Boolean] :force (false)
30
+ # @private
31
+ def build_internal(filename, options = {})
32
+ build_once(filename, options[:force]) do |content, id|
33
+ raw_format = parse_json(content)
34
+
35
+ # Check the compatibility of specified layout file.
36
+ unless ThinReports::Layout::Version.compatible?(raw_format['version'])
37
+ info = [filename, raw_format['version'],
38
+ ThinReports::Layout::Version.required_rules_inspect]
39
+ raise ThinReports::Errors::IncompatibleLayoutFormat.new(*info)
40
+ end
41
+
42
+ # Build and initialize format.
43
+ new(raw_format, id) do |f|
44
+ build_layout(f) do |type, shape_format|
45
+ Core::Shape::Format(type).build(shape_format)
46
+ end
47
+ clean(f.layout)
48
+ end
49
+ end
50
+ end
51
+
52
+ # @private
53
+ def build_once(filename, force = false, &block)
54
+ content = read_format_file(filename)
55
+
56
+ if force
57
+ block.call(content, nil)
58
+ else
59
+ id = Digest::SHA1.hexdigest(content).to_sym
60
+ built_format_registry[id] ||= block.call(content, id)
61
+ end
62
+ end
63
+
64
+ # @private
65
+ def read_format_file(filename)
66
+ File.open(filename, 'r:UTF-8') {|f| f.read }
67
+ end
68
+
69
+ # @private
70
+ def built_format_registry
71
+ @built_format_registry ||= {}
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end