caracal 0.1.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 (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