caracal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +941 -0
  6. data/Rakefile +2 -0
  7. data/caracal.gemspec +27 -0
  8. data/lib/caracal.rb +31 -0
  9. data/lib/caracal/core/file_name.rb +39 -0
  10. data/lib/caracal/core/fonts.rb +75 -0
  11. data/lib/caracal/core/images.rb +37 -0
  12. data/lib/caracal/core/line_breaks.rb +29 -0
  13. data/lib/caracal/core/list_styles.rb +92 -0
  14. data/lib/caracal/core/lists.rb +57 -0
  15. data/lib/caracal/core/models/base_model.rb +51 -0
  16. data/lib/caracal/core/models/border_model.rb +120 -0
  17. data/lib/caracal/core/models/font_model.rb +64 -0
  18. data/lib/caracal/core/models/image_model.rb +118 -0
  19. data/lib/caracal/core/models/line_break_model.rb +15 -0
  20. data/lib/caracal/core/models/link_model.rb +65 -0
  21. data/lib/caracal/core/models/list_item_model.rb +105 -0
  22. data/lib/caracal/core/models/list_model.rb +130 -0
  23. data/lib/caracal/core/models/list_style_model.rb +129 -0
  24. data/lib/caracal/core/models/margin_model.rb +76 -0
  25. data/lib/caracal/core/models/page_break_model.rb +15 -0
  26. data/lib/caracal/core/models/page_number_model.rb +69 -0
  27. data/lib/caracal/core/models/page_size_model.rb +70 -0
  28. data/lib/caracal/core/models/paragraph_model.rb +141 -0
  29. data/lib/caracal/core/models/relationship_model.rb +108 -0
  30. data/lib/caracal/core/models/rule_model.rb +27 -0
  31. data/lib/caracal/core/models/style_model.rb +134 -0
  32. data/lib/caracal/core/models/table_cell_model.rb +155 -0
  33. data/lib/caracal/core/models/table_model.rb +206 -0
  34. data/lib/caracal/core/models/text_model.rb +92 -0
  35. data/lib/caracal/core/page_breaks.rb +29 -0
  36. data/lib/caracal/core/page_numbers.rb +51 -0
  37. data/lib/caracal/core/page_settings.rb +72 -0
  38. data/lib/caracal/core/relationships.rb +90 -0
  39. data/lib/caracal/core/rules.rb +35 -0
  40. data/lib/caracal/core/styles.rb +86 -0
  41. data/lib/caracal/core/tables.rb +41 -0
  42. data/lib/caracal/core/text.rb +73 -0
  43. data/lib/caracal/document.rb +242 -0
  44. data/lib/caracal/errors.rb +23 -0
  45. data/lib/caracal/renderers/app_renderer.rb +41 -0
  46. data/lib/caracal/renderers/content_types_renderer.rb +53 -0
  47. data/lib/caracal/renderers/core_renderer.rb +44 -0
  48. data/lib/caracal/renderers/document_renderer.rb +349 -0
  49. data/lib/caracal/renderers/fonts_renderer.rb +56 -0
  50. data/lib/caracal/renderers/footer_renderer.rb +69 -0
  51. data/lib/caracal/renderers/numbering_renderer.rb +87 -0
  52. data/lib/caracal/renderers/package_relationships_renderer.rb +50 -0
  53. data/lib/caracal/renderers/relationships_renderer.rb +48 -0
  54. data/lib/caracal/renderers/settings_renderer.rb +58 -0
  55. data/lib/caracal/renderers/styles_renderer.rb +163 -0
  56. data/lib/caracal/renderers/xml_renderer.rb +83 -0
  57. data/lib/caracal/version.rb +3 -0
  58. data/lib/tilt/caracal.rb +21 -0
  59. data/spec/lib/caracal/core/file_name_spec.rb +54 -0
  60. data/spec/lib/caracal/core/fonts_spec.rb +119 -0
  61. data/spec/lib/caracal/core/images_spec.rb +25 -0
  62. data/spec/lib/caracal/core/line_breaks_spec.rb +25 -0
  63. data/spec/lib/caracal/core/list_styles_spec.rb +121 -0
  64. data/spec/lib/caracal/core/lists_spec.rb +43 -0
  65. data/spec/lib/caracal/core/models/base_model_spec.rb +38 -0
  66. data/spec/lib/caracal/core/models/border_model_spec.rb +159 -0
  67. data/spec/lib/caracal/core/models/font_model_spec.rb +92 -0
  68. data/spec/lib/caracal/core/models/image_model_spec.rb +192 -0
  69. data/spec/lib/caracal/core/models/line_break_model_spec.rb +21 -0
  70. data/spec/lib/caracal/core/models/link_model_spec.rb +139 -0
  71. data/spec/lib/caracal/core/models/list_item_model_spec.rb +190 -0
  72. data/spec/lib/caracal/core/models/list_model_spec.rb +178 -0
  73. data/spec/lib/caracal/core/models/list_style_model_spec.rb +212 -0
  74. data/spec/lib/caracal/core/models/margin_model_spec.rb +111 -0
  75. data/spec/lib/caracal/core/models/page_break_model_spec.rb +21 -0
  76. data/spec/lib/caracal/core/models/page_number_model_spec.rb +101 -0
  77. data/spec/lib/caracal/core/models/page_size_model_spec.rb +91 -0
  78. data/spec/lib/caracal/core/models/paragraph_model_spec.rb +162 -0
  79. data/spec/lib/caracal/core/models/relationship_model_spec.rb +183 -0
  80. data/spec/lib/caracal/core/models/rule_model_spec.rb +108 -0
  81. data/spec/lib/caracal/core/models/style_model_spec.rb +187 -0
  82. data/spec/lib/caracal/core/models/table_cell_model_spec.rb +221 -0
  83. data/spec/lib/caracal/core/models/table_model_spec.rb +222 -0
  84. data/spec/lib/caracal/core/models/text_model_spec.rb +132 -0
  85. data/spec/lib/caracal/core/page_breaks_spec.rb +25 -0
  86. data/spec/lib/caracal/core/page_numbers_spec.rb +80 -0
  87. data/spec/lib/caracal/core/page_settings_spec.rb +143 -0
  88. data/spec/lib/caracal/core/relationships_spec.rb +119 -0
  89. data/spec/lib/caracal/core/rules_spec.rb +25 -0
  90. data/spec/lib/caracal/core/styles_spec.rb +129 -0
  91. data/spec/lib/caracal/core/tables_spec.rb +25 -0
  92. data/spec/lib/caracal/core/text_spec.rb +52 -0
  93. data/spec/lib/caracal/errors_spec.rb +10 -0
  94. data/spec/spec_helper.rb +8 -0
  95. metadata +245 -0
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/caracal.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'caracal/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'caracal'
8
+ spec.version = Caracal::VERSION
9
+ spec.authors = ['Trade Infomatics', 'John Dugan']
10
+ spec.email = ['jpdugan@gmail.com']
11
+ spec.summary = %q{ Fast, professional MSWord writer for Ruby. }
12
+ spec.description = %q{ Caracal is a pure Ruby MSWord generation library that produces professional quality Word documents using a simple, HTML-style DSL. }
13
+ spec.homepage = 'https://github.com/trade-informatics/caracal'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'nokogiri', '~> 1.6'
22
+ spec.add_dependency 'rubyzip', '~> 1.1'
23
+ spec.add_dependency 'tilt', '~> 1.4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.6'
26
+ spec.add_development_dependency 'rspec', '~> 3.0'
27
+ end
data/lib/caracal.rb ADDED
@@ -0,0 +1,31 @@
1
+ #------------------------------------------------
2
+ # Requirements
3
+ #------------------------------------------------
4
+
5
+ # external dependencies
6
+ require 'tilt'
7
+
8
+ # odds & ends
9
+ require 'caracal/errors'
10
+ require 'caracal/version'
11
+
12
+ # document
13
+ require 'caracal/document'
14
+
15
+
16
+ #------------------------------------------------
17
+ # Extra Setup
18
+ #------------------------------------------------
19
+
20
+ # Add functions to table cell model. we do this here to
21
+ # avoid a circular require between Caracal::Core::Tables
22
+ # and Caracal::Core::Models::TableCellModel.
23
+ #
24
+ Caracal::Core::Models::TableCellModel.class_eval do
25
+ include Caracal::Core::Images
26
+ include Caracal::Core::LineBreaks
27
+ include Caracal::Core::Lists
28
+ include Caracal::Core::Rules
29
+ include Caracal::Core::Tables
30
+ include Caracal::Core::Text
31
+ end
@@ -0,0 +1,39 @@
1
+ module Caracal
2
+ module Core
3
+
4
+ # This module encapsulates all the functionality related to setting the
5
+ # document's name.
6
+ #
7
+ module FileName
8
+ def self.included(base)
9
+ base.class_eval do
10
+
11
+ #-------------------------------------------------------------
12
+ # Configuration
13
+ #-------------------------------------------------------------
14
+
15
+ # constants
16
+ const_set(:DEFAULT_FILE_NAME, 'caracal.docx')
17
+
18
+ # accessors
19
+ attr_reader :name
20
+
21
+
22
+ #-------------------------------------------------------------
23
+ # Public Methods
24
+ #-------------------------------------------------------------
25
+
26
+ # This method sets the name of the output file. Defaults
27
+ # to the name of the library.
28
+ #
29
+ def file_name(value = nil)
30
+ v = value.to_s.strip
31
+ @name = (v == '') ? self.class::DEFAULT_FILE_NAME : v
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,75 @@
1
+ require 'caracal/core/models/font_model'
2
+ require 'caracal/errors'
3
+
4
+
5
+ module Caracal
6
+ module Core
7
+
8
+ # This module encapsulates all the functionality related to registering
9
+ # fonts.
10
+ #
11
+ module Fonts
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ #-------------------------------------------------------------
16
+ # Class Methods
17
+ #-------------------------------------------------------------
18
+
19
+ def self.default_fonts
20
+ [
21
+ { name: 'Arial' },
22
+ { name: 'Trebuchet MS' }
23
+ ]
24
+ end
25
+
26
+
27
+ #-------------------------------------------------------------
28
+ # Public Methods
29
+ #-------------------------------------------------------------
30
+
31
+ #============== ATTRIBUTES ==========================
32
+
33
+ def font(opts, &block)
34
+ model = Caracal::Core::Models::FontModel.new(opts, &block)
35
+
36
+ if model.valid?
37
+ register_font(model)
38
+ else
39
+ raise Caracal::Errors::InvalidModelError, 'font must specify the :name attribute.'
40
+ end
41
+ model
42
+ end
43
+
44
+
45
+ #============== GETTERS =============================
46
+
47
+ def fonts
48
+ @fonts ||= []
49
+ end
50
+
51
+ def find_font(name)
52
+ fonts.find { |f| f.matches?(name) }
53
+ end
54
+
55
+
56
+ #============== REGISTRATION ========================
57
+
58
+ def register_font(model)
59
+ unregister_font(model.font_name)
60
+ fonts << model
61
+ model
62
+ end
63
+
64
+ def unregister_font(name)
65
+ if f = find_font(name)
66
+ fonts.delete(f)
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,37 @@
1
+ require 'caracal/core/models/image_model'
2
+ require 'caracal/errors'
3
+
4
+
5
+ module Caracal
6
+ module Core
7
+
8
+ # This module encapsulates all the functionality related to adding
9
+ # images to the document.
10
+ #
11
+ module Images
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ #-------------------------------------------------------------
16
+ # Public Methods
17
+ #-------------------------------------------------------------
18
+
19
+ def img(*text, **options, &block)
20
+ text.flatten!
21
+ options.merge!( { url: text[0] }) unless text[0].nil?
22
+
23
+ model = Caracal::Core::Models::ImageModel.new(options, &block)
24
+ if model.valid?
25
+ contents << model
26
+ else
27
+ raise Caracal::Errors::InvalidModelError, 'Images require an URL and positive size/margin values.'
28
+ end
29
+ model
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ require 'caracal/core/models/line_break_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+
7
+ # This module encapsulates all the functionality related to adding line
8
+ # breaks to the document.
9
+ #
10
+ module LineBreaks
11
+ def self.included(base)
12
+ base.class_eval do
13
+
14
+ #-------------------------------------------------------------
15
+ # Public Methods
16
+ #-------------------------------------------------------------
17
+
18
+ def br
19
+ model = Caracal::Core::Models::LineBreakModel.new()
20
+ contents << model
21
+ model
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,92 @@
1
+ require 'caracal/core/models/list_style_model'
2
+ require 'caracal/errors'
3
+
4
+
5
+ module Caracal
6
+ module Core
7
+
8
+ # This module encapsulates all the functionality related to defining
9
+ # list styles.
10
+ #
11
+ module ListStyles
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ #-------------------------------------------------------------
16
+ # Class Methods
17
+ #-------------------------------------------------------------
18
+
19
+ def self.default_list_styles
20
+ [
21
+ { type: :ordered, level: 0, format: 'decimal', value: '%1.', left: 720, line: 360 },
22
+ { type: :ordered, level: 1, format: 'lowerLetter', value: '%2.', left: 1440, line: 1080 },
23
+ { type: :ordered, level: 2, format: 'lowerRoman', value: '%3.', left: 2160, line: 1800, align: :right },
24
+ { type: :ordered, level: 3, format: 'decimal', value: '%4.', left: 2880, line: 2520 },
25
+ { type: :ordered, level: 4, format: 'lowerLetter', value: '%5.', left: 3600, line: 3240 },
26
+ { type: :ordered, level: 5, format: 'lowerRoman', value: '%6.', left: 4320, line: 3960, align: :right },
27
+ { type: :ordered, level: 6, format: 'decimal', value: '%7.', left: 5040, line: 4680 },
28
+ { type: :ordered, level: 7, format: 'lowerLetter', value: '%8.', left: 5760, line: 5400 },
29
+ { type: :ordered, level: 8, format: 'lowerRoman', value: '%9.', left: 6480, line: 6120, align: :right },
30
+
31
+ { type: :unordered, level: 0, format: 'bullet', value: '●', left: 720, line: 360 },
32
+ { type: :unordered, level: 1, format: 'bullet', value: '○', left: 1440, line: 1080 },
33
+ { type: :unordered, level: 2, format: 'bullet', value: '■', left: 2160, line: 1800 },
34
+ { type: :unordered, level: 3, format: 'bullet', value: '●', left: 2880, line: 2520 },
35
+ { type: :unordered, level: 4, format: 'bullet', value: '○', left: 3600, line: 3240 },
36
+ { type: :unordered, level: 5, format: 'bullet', value: '■', left: 4320, line: 3960 },
37
+ { type: :unordered, level: 6, format: 'bullet', value: '●', left: 5040, line: 4680 },
38
+ { type: :unordered, level: 7, format: 'bullet', value: '○', left: 5760, line: 5400 },
39
+ { type: :unordered, level: 8, format: 'bullet', value: '■', left: 6480, line: 6120 }
40
+ ]
41
+ end
42
+
43
+
44
+ #-------------------------------------------------------------
45
+ # Public Methods
46
+ #-------------------------------------------------------------
47
+
48
+ #============== ATTRIBUTES ==========================
49
+
50
+ def list_style(**options, &block)
51
+ model = Caracal::Core::Models::ListStyleModel.new(options, &block)
52
+
53
+ if model.valid?
54
+ register_list_style(model)
55
+ else
56
+ raise Caracal::Errors::InvalidModelError, 'list style must define a :type, :level, :format, and :value.'
57
+ end
58
+ model
59
+ end
60
+
61
+
62
+ #============== GETTERS =============================
63
+
64
+ def list_styles
65
+ @list_styles ||= []
66
+ end
67
+
68
+ def find_list_style(type, level)
69
+ list_styles.find { |s| s.matches?(type, level) }
70
+ end
71
+
72
+
73
+ #============== REGISTRATION ========================
74
+
75
+ def register_list_style(model)
76
+ unregister_list_style(model.style_type, model.style_level)
77
+ list_styles << model
78
+ model
79
+ end
80
+
81
+ def unregister_list_style(type, level)
82
+ if s = find_list_style(type, level)
83
+ list_styles.delete(s)
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,57 @@
1
+ require 'caracal/core/models/list_model'
2
+ require 'caracal/errors'
3
+
4
+
5
+ module Caracal
6
+ module Core
7
+
8
+ # This module encapsulates all the functionality related to adding
9
+ # horizontal rules to the document.
10
+ #
11
+ module Lists
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ #-------------------------------------------------------------
16
+ # Public Methods
17
+ #-------------------------------------------------------------
18
+
19
+ #============== ATTRIBUTES ==========================
20
+
21
+ def ol(**options, &block)
22
+ options.merge!({ type: :ordered, level: 0 })
23
+
24
+ model = Caracal::Core::Models::ListModel.new(options, &block)
25
+ if model.valid?
26
+ contents << model
27
+ else
28
+ raise Caracal::Errors::InvalidModelError, 'Ordered lists require at least one list item.'
29
+ end
30
+ model
31
+ end
32
+
33
+ def ul(**options, &block)
34
+ options.merge!({ type: :unordered, level: 0 })
35
+
36
+ model = Caracal::Core::Models::ListModel.new(options, &block)
37
+ if model.valid?
38
+ contents << model
39
+ else
40
+ raise Caracal::Errors::InvalidModelError, 'Unordered lists require at least one list item.'
41
+ end
42
+ model
43
+ end
44
+
45
+
46
+ #============== GETTERS ==========================
47
+
48
+ def toplevel_lists
49
+ @toplevel_lists ||= []
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ module Caracal
2
+ module Core
3
+ module Models
4
+
5
+ # This class encapsulates the logic needed for functions that
6
+ # do not store or manipulate data.
7
+ #
8
+ class BaseModel
9
+
10
+ #-------------------------------------------------------------
11
+ # Configuration
12
+ #-------------------------------------------------------------
13
+
14
+ # initialization
15
+ def initialize(**options, &block)
16
+ options.keep_if { |k,v| option_keys.include? k }
17
+ options.each do |(key, value)|
18
+ send(key, value)
19
+ end
20
+
21
+ if block_given?
22
+ (block.arity < 1) ? instance_eval(&block) : block[self]
23
+ end
24
+ end
25
+
26
+
27
+ #-------------------------------------------------------------
28
+ # Public Instance Methods
29
+ #-------------------------------------------------------------
30
+
31
+ #=============== VALIDATION ===========================
32
+
33
+ def valid?
34
+ true
35
+ end
36
+
37
+
38
+ #-------------------------------------------------------------
39
+ # Private Instance Methods
40
+ #-------------------------------------------------------------
41
+ private
42
+
43
+ def option_keys
44
+ []
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
51
+ end