caracal_the_curve 1.4.1

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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +22 -0
  3. data/.github/workflows/publish_gem.yml +40 -0
  4. data/.gitignore +25 -0
  5. data/.travis.yml +20 -0
  6. data/CHANGELOG.md +141 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +842 -0
  10. data/Rakefile +7 -0
  11. data/caracal.gemspec +28 -0
  12. data/lib/caracal/core/bookmarks.rb +52 -0
  13. data/lib/caracal/core/custom_properties.rb +49 -0
  14. data/lib/caracal/core/file_name.rb +43 -0
  15. data/lib/caracal/core/fonts.rb +75 -0
  16. data/lib/caracal/core/iframes.rb +42 -0
  17. data/lib/caracal/core/ignorables.rb +47 -0
  18. data/lib/caracal/core/images.rb +37 -0
  19. data/lib/caracal/core/list_styles.rb +93 -0
  20. data/lib/caracal/core/lists.rb +57 -0
  21. data/lib/caracal/core/models/base_model.rb +51 -0
  22. data/lib/caracal/core/models/bookmark_model.rb +86 -0
  23. data/lib/caracal/core/models/border_model.rb +120 -0
  24. data/lib/caracal/core/models/custom_property_model.rb +60 -0
  25. data/lib/caracal/core/models/font_model.rb +64 -0
  26. data/lib/caracal/core/models/iframe_model.rb +148 -0
  27. data/lib/caracal/core/models/image_model.rb +133 -0
  28. data/lib/caracal/core/models/line_break_model.rb +15 -0
  29. data/lib/caracal/core/models/link_model.rb +94 -0
  30. data/lib/caracal/core/models/list_item_model.rb +108 -0
  31. data/lib/caracal/core/models/list_model.rb +132 -0
  32. data/lib/caracal/core/models/list_style_model.rb +118 -0
  33. data/lib/caracal/core/models/margin_model.rb +76 -0
  34. data/lib/caracal/core/models/namespace_model.rb +65 -0
  35. data/lib/caracal/core/models/page_break_model.rb +61 -0
  36. data/lib/caracal/core/models/page_number_model.rb +95 -0
  37. data/lib/caracal/core/models/page_size_model.rb +79 -0
  38. data/lib/caracal/core/models/paragraph_model.rb +186 -0
  39. data/lib/caracal/core/models/relationship_model.rb +114 -0
  40. data/lib/caracal/core/models/rule_model.rb +27 -0
  41. data/lib/caracal/core/models/style_model.rb +165 -0
  42. data/lib/caracal/core/models/table_cell_model.rb +176 -0
  43. data/lib/caracal/core/models/table_model.rb +206 -0
  44. data/lib/caracal/core/models/text_model.rb +118 -0
  45. data/lib/caracal/core/namespaces.rb +89 -0
  46. data/lib/caracal/core/page_breaks.rb +29 -0
  47. data/lib/caracal/core/page_numbers.rb +58 -0
  48. data/lib/caracal/core/page_settings.rb +74 -0
  49. data/lib/caracal/core/relationships.rb +90 -0
  50. data/lib/caracal/core/rules.rb +35 -0
  51. data/lib/caracal/core/styles.rb +86 -0
  52. data/lib/caracal/core/tables.rb +42 -0
  53. data/lib/caracal/core/text.rb +75 -0
  54. data/lib/caracal/document.rb +272 -0
  55. data/lib/caracal/errors.rb +23 -0
  56. data/lib/caracal/renderers/app_renderer.rb +41 -0
  57. data/lib/caracal/renderers/content_types_renderer.rb +54 -0
  58. data/lib/caracal/renderers/core_renderer.rb +44 -0
  59. data/lib/caracal/renderers/custom_renderer.rb +64 -0
  60. data/lib/caracal/renderers/document_renderer.rb +427 -0
  61. data/lib/caracal/renderers/fonts_renderer.rb +56 -0
  62. data/lib/caracal/renderers/footer_renderer.rb +90 -0
  63. data/lib/caracal/renderers/numbering_renderer.rb +88 -0
  64. data/lib/caracal/renderers/package_relationships_renderer.rb +51 -0
  65. data/lib/caracal/renderers/relationships_renderer.rb +48 -0
  66. data/lib/caracal/renderers/settings_renderer.rb +58 -0
  67. data/lib/caracal/renderers/styles_renderer.rb +181 -0
  68. data/lib/caracal/renderers/xml_renderer.rb +83 -0
  69. data/lib/caracal/utilities.rb +23 -0
  70. data/lib/caracal/version.rb +3 -0
  71. data/lib/caracal.rb +40 -0
  72. data/lib/tilt/caracal.rb +21 -0
  73. data/spec/lib/caracal/core/bookmarks_spec.rb +35 -0
  74. data/spec/lib/caracal/core/file_name_spec.rb +54 -0
  75. data/spec/lib/caracal/core/fonts_spec.rb +119 -0
  76. data/spec/lib/caracal/core/iframes_spec.rb +29 -0
  77. data/spec/lib/caracal/core/ignorables_spec.rb +79 -0
  78. data/spec/lib/caracal/core/images_spec.rb +25 -0
  79. data/spec/lib/caracal/core/list_styles_spec.rb +121 -0
  80. data/spec/lib/caracal/core/lists_spec.rb +43 -0
  81. data/spec/lib/caracal/core/models/base_model_spec.rb +38 -0
  82. data/spec/lib/caracal/core/models/bookmark_model_spec.rb +135 -0
  83. data/spec/lib/caracal/core/models/border_model_spec.rb +159 -0
  84. data/spec/lib/caracal/core/models/font_model_spec.rb +92 -0
  85. data/spec/lib/caracal/core/models/iframe_model_spec.rb +83 -0
  86. data/spec/lib/caracal/core/models/image_model_spec.rb +225 -0
  87. data/spec/lib/caracal/core/models/line_break_model_spec.rb +21 -0
  88. data/spec/lib/caracal/core/models/link_model_spec.rb +179 -0
  89. data/spec/lib/caracal/core/models/list_item_model_spec.rb +197 -0
  90. data/spec/lib/caracal/core/models/list_model_spec.rb +178 -0
  91. data/spec/lib/caracal/core/models/list_style_model_spec.rb +198 -0
  92. data/spec/lib/caracal/core/models/margin_model_spec.rb +111 -0
  93. data/spec/lib/caracal/core/models/namespace_model_spec.rb +107 -0
  94. data/spec/lib/caracal/core/models/page_break_model_spec.rb +21 -0
  95. data/spec/lib/caracal/core/models/page_number_model_spec.rb +136 -0
  96. data/spec/lib/caracal/core/models/page_size_model_spec.rb +101 -0
  97. data/spec/lib/caracal/core/models/paragraph_model_spec.rb +196 -0
  98. data/spec/lib/caracal/core/models/relationship_model_spec.rb +193 -0
  99. data/spec/lib/caracal/core/models/rule_model_spec.rb +108 -0
  100. data/spec/lib/caracal/core/models/style_model_spec.rb +225 -0
  101. data/spec/lib/caracal/core/models/table_cell_model_spec.rb +230 -0
  102. data/spec/lib/caracal/core/models/table_model_spec.rb +222 -0
  103. data/spec/lib/caracal/core/models/text_model_spec.rb +154 -0
  104. data/spec/lib/caracal/core/namespaces_spec.rb +116 -0
  105. data/spec/lib/caracal/core/page_breaks_spec.rb +25 -0
  106. data/spec/lib/caracal/core/page_numbers_spec.rb +89 -0
  107. data/spec/lib/caracal/core/page_settings_spec.rb +151 -0
  108. data/spec/lib/caracal/core/relationships_spec.rb +119 -0
  109. data/spec/lib/caracal/core/rules_spec.rb +25 -0
  110. data/spec/lib/caracal/core/styles_spec.rb +129 -0
  111. data/spec/lib/caracal/core/tables_spec.rb +25 -0
  112. data/spec/lib/caracal/core/text_spec.rb +52 -0
  113. data/spec/lib/caracal/errors_spec.rb +10 -0
  114. data/spec/spec_helper.rb +8 -0
  115. data/spec/support/_fixtures/snippet.docx +0 -0
  116. metadata +292 -0
@@ -0,0 +1,120 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class handles block options passed to the page margins
9
+ # method.
10
+ #
11
+ class BorderModel < BaseModel
12
+
13
+ #-------------------------------------------------------------
14
+ # Configuration
15
+ #-------------------------------------------------------------
16
+
17
+ # constants
18
+ const_set(:DEFAULT_BORDER_COLOR, 'auto')
19
+ const_set(:DEFAULT_BORDER_LINE, :single)
20
+ const_set(:DEFAULT_BORDER_SIZE, 4) # 0.5pt in 1/8 points
21
+ const_set(:DEFAULT_BORDER_SPACING, 1) # 0.125pt in 1/8 points
22
+ const_set(:DEFAULT_BORDER_TYPE, :top)
23
+
24
+ # accessors
25
+ attr_reader :border_color
26
+ attr_reader :border_line
27
+ attr_reader :border_size
28
+ attr_reader :border_spacing
29
+ attr_reader :border_type
30
+
31
+ # initialization
32
+ def initialize(options={}, &block)
33
+ @border_color = DEFAULT_BORDER_COLOR
34
+ @border_line = DEFAULT_BORDER_LINE
35
+ @border_size = DEFAULT_BORDER_SIZE
36
+ @border_spacing = DEFAULT_BORDER_SPACING
37
+ @border_type = DEFAULT_BORDER_TYPE
38
+
39
+ super options, &block
40
+ end
41
+
42
+
43
+ #-------------------------------------------------------------
44
+ # Class Methods
45
+ #-------------------------------------------------------------
46
+
47
+ def self.formatted_type(type)
48
+ case type.to_s.to_sym
49
+ when :horizontal then 'insideH'
50
+ when :vertical then 'insideV'
51
+ when :top then 'top'
52
+ when :bottom then 'bottom'
53
+ when :left then 'left'
54
+ when :right then 'right'
55
+ else nil
56
+ end
57
+ end
58
+
59
+
60
+ #-------------------------------------------------------------
61
+ # Public Methods
62
+ #-------------------------------------------------------------
63
+
64
+ #=============== GETTERS ==============================
65
+
66
+ def formatted_type
67
+ self.class.formatted_type(border_type)
68
+ end
69
+
70
+ def total_size
71
+ border_size + (2 * border_spacing)
72
+ end
73
+
74
+
75
+ #=============== SETTERS ==============================
76
+
77
+ # integers
78
+ [:size, :spacing].each do |m|
79
+ define_method "#{ m }" do |value|
80
+ instance_variable_set("@border_#{ m }", value.to_i)
81
+ end
82
+ end
83
+
84
+ # strings
85
+ [:color].each do |m|
86
+ define_method "#{ m }" do |value|
87
+ instance_variable_set("@border_#{ m }", value.to_s)
88
+ end
89
+ end
90
+
91
+ # symbols
92
+ [:line, :type].each do |m|
93
+ define_method "#{ m }" do |value|
94
+ instance_variable_set("@border_#{ m }", value.to_s.to_sym)
95
+ end
96
+ end
97
+
98
+
99
+ #=============== VALIDATION ==============================
100
+
101
+ def valid?
102
+ dims = [border_size, border_spacing]
103
+ dims.all? { |d| d > 0 }
104
+ end
105
+
106
+
107
+ #-------------------------------------------------------------
108
+ # Private Instance Methods
109
+ #-------------------------------------------------------------
110
+ private
111
+
112
+ def option_keys
113
+ [:color, :line, :size, :spacing, :type]
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,60 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class encapsulates the logic needed to store and manipulate
9
+ # custom properties
10
+ #
11
+ class CustomPropertyModel < BaseModel
12
+
13
+ # accessors
14
+ attr_reader :custom_property_name
15
+ attr_reader :custom_property_value
16
+ attr_reader :custom_property_type
17
+
18
+
19
+ #-------------------------------------------------------------
20
+ # Public Instance Methods
21
+ #-------------------------------------------------------------
22
+
23
+
24
+ #=================== SETTERS =============================
25
+
26
+ def name(value)
27
+ @custom_property_name = value.to_s
28
+ end
29
+
30
+ def value(value)
31
+ @custom_property_value = value.to_s
32
+ end
33
+
34
+ def type(value)
35
+ @custom_property_type = value.to_s
36
+ end
37
+
38
+
39
+ #=============== VALIDATION ===========================
40
+
41
+ def valid?
42
+ required = option_keys
43
+ required.all? { |m| !send("custom_property_#{ m }").nil? }
44
+ end
45
+
46
+
47
+ #-------------------------------------------------------------
48
+ # Private Instance Methods
49
+ #-------------------------------------------------------------
50
+ private
51
+
52
+ def option_keys
53
+ [:name, :value, :type]
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,64 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class encapsulates the logic needed to store and manipulate
9
+ # font data.
10
+ #
11
+ class FontModel < BaseModel
12
+
13
+ #-------------------------------------------------------------
14
+ # Configuration
15
+ #-------------------------------------------------------------
16
+
17
+ # accessors
18
+ attr_reader :font_name
19
+
20
+
21
+
22
+ #-------------------------------------------------------------
23
+ # Public Instance Methods
24
+ #-------------------------------------------------------------
25
+
26
+ #=============== SETTERS ==============================
27
+
28
+ # strings
29
+ [:name].each do |m|
30
+ define_method "#{ m }" do |value|
31
+ instance_variable_set("@font_#{ m }", value.to_s)
32
+ end
33
+ end
34
+
35
+
36
+ #=============== STATE ================================
37
+
38
+ def matches?(str)
39
+ font_name.to_s.downcase == str.to_s.downcase
40
+ end
41
+
42
+
43
+ #=============== VALIDATION ===========================
44
+
45
+ def valid?
46
+ a = [:name]
47
+ a.map { |m| send("font_#{ m }") }.compact.size == a.size
48
+ end
49
+
50
+
51
+ #-------------------------------------------------------------
52
+ # Private Instance Methods
53
+ #-------------------------------------------------------------
54
+ private
55
+
56
+ def option_keys
57
+ [:name]
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,148 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+ module Caracal
4
+ module Core
5
+ module Models
6
+
7
+ # This class handles block options passed to the img method.
8
+ #
9
+ class IFrameModel < BaseModel
10
+
11
+ #--------------------------------------------------
12
+ # Configuration
13
+ #--------------------------------------------------
14
+
15
+ # accessors
16
+ attr_reader :iframe_url
17
+ attr_reader :iframe_data
18
+ attr_reader :iframe_ignorables
19
+ attr_reader :iframe_namespaces
20
+ attr_reader :iframe_relationships
21
+
22
+ # initialization
23
+ def initialize(options={}, &block)
24
+ super options, &block
25
+ end
26
+
27
+
28
+ #--------------------------------------------------
29
+ # Public Methods
30
+ #--------------------------------------------------
31
+
32
+ #=============== PROCESSING =======================
33
+
34
+ def preprocess!
35
+ ::Zip::File.open(file) do |zip|
36
+ # locate relationships xml
37
+ entry = zip.glob('word/_rels/document.xml.rels').first
38
+ content = entry.get_input_stream.read
39
+ rel_xml = Nokogiri::XML(content)
40
+
41
+ # locate document xml
42
+ entry = zip.glob('word/document.xml').first
43
+ content = entry.get_input_stream.read
44
+ doc_xml = Nokogiri::XML(content)
45
+
46
+ # master nodesets
47
+ rel_nodes = rel_xml.children.first.children
48
+ doc_root = doc_xml.at_xpath('//w:document')
49
+ pic_nodes = doc_xml.xpath('//pic:pic', { pic: 'http://schemas.openxmlformats.org/drawingml/2006/picture' })
50
+
51
+ # namespaces
52
+ @iframe_namespaces = doc_root.namespaces
53
+
54
+ # ignorable namespaces
55
+ if a = doc_root.attributes['Ignorable']
56
+ @iframe_ignorables = a.value.split(/\s+/)
57
+ end
58
+
59
+ # relationships
60
+ media_map = rel_nodes.reduce({}) do |hash, node|
61
+ type = node.at_xpath('@Type').value
62
+ if type.slice(-5, 5) == 'image'
63
+ id = node.at_xpath('@Id').value
64
+ path = "word/#{ node.at_xpath('@Target').value }"
65
+ hash[id] = path
66
+ end
67
+ hash
68
+ end
69
+ @iframe_relationships = pic_nodes.reduce([]) do |array, node|
70
+ r_node = node.children[1].children[0]
71
+ r_id = r_node.attributes['embed'].value.to_s
72
+ r_media = media_map[r_id]
73
+
74
+ p_node = node.children[0].children[0]
75
+ p_id = p_node.attributes['id'].to_s.to_i
76
+ p_name = p_node.attributes['name'].to_s
77
+ p_data = zip.glob(r_media).first.get_input_stream.read
78
+
79
+ # register relationship
80
+ array << { id: r_id, type: 'image', target: p_name, data: p_data }
81
+ array
82
+ end
83
+ end
84
+ end
85
+
86
+
87
+ #=============== GETTERS ==========================
88
+
89
+ def file
90
+ @file ||= begin
91
+ if iframe_url.nil?
92
+ file = Tempfile.new('iframe')
93
+ file.write iframe_data
94
+ file.rewind
95
+ else
96
+ file = open(iframe_url)
97
+ end
98
+ file
99
+ end
100
+ end
101
+
102
+ def ignorables
103
+ @iframe_ignorables || []
104
+ end
105
+
106
+ def namespaces
107
+ @iframe_namespaces || {}
108
+ end
109
+
110
+ def relationships
111
+ @iframe_relationships || []
112
+ end
113
+
114
+
115
+ #=============== SETTERS ==========================
116
+
117
+ # strings
118
+ [:data, :url].each do |m|
119
+ define_method "#{ m }" do |value|
120
+ instance_variable_set("@iframe_#{ m }", value.to_s)
121
+ end
122
+ end
123
+
124
+
125
+ #=============== VALIDATION =======================
126
+
127
+ def valid?
128
+ vals = option_keys.map { |m| send("iframe_#{ m }") }.compact
129
+ vals = vals.reject { |v| v.size == 0 }
130
+ vals.size > 0
131
+ end
132
+
133
+
134
+
135
+ #--------------------------------------------------
136
+ # Private Methods
137
+ #--------------------------------------------------
138
+ private
139
+
140
+ def option_keys
141
+ [:url, :data]
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,133 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class handles block options passed to the img method.
9
+ #
10
+ class ImageModel < BaseModel
11
+
12
+ #-------------------------------------------------------------
13
+ # Configuration
14
+ #-------------------------------------------------------------
15
+
16
+ # constants
17
+ const_set(:DEFAULT_IMAGE_PPI, 72) # pixels per inch
18
+ const_set(:DEFAULT_IMAGE_WIDTH, 0) # units in pixels. (will cause error)
19
+ const_set(:DEFAULT_IMAGE_HEIGHT, 0) # units in pixels. (will cause error)
20
+ const_set(:DEFAULT_IMAGE_ALIGN, :left)
21
+ const_set(:DEFAULT_IMAGE_TOP, 8) # units in pixels.
22
+ const_set(:DEFAULT_IMAGE_BOTTOM, 8) # units in pixels.
23
+ const_set(:DEFAULT_IMAGE_LEFT, 8) # units in pixels.
24
+ const_set(:DEFAULT_IMAGE_RIGHT, 8) # units in pixels.
25
+
26
+ # accessors
27
+ attr_reader :image_url
28
+ attr_reader :image_data
29
+ attr_reader :image_ppi
30
+ attr_reader :image_width
31
+ attr_reader :image_height
32
+ attr_reader :image_align
33
+ attr_reader :image_top
34
+ attr_reader :image_bottom
35
+ attr_reader :image_left
36
+ attr_reader :image_right
37
+
38
+
39
+ # initialization
40
+ def initialize(options={}, &block)
41
+ @image_ppi = DEFAULT_IMAGE_PPI
42
+ @image_width = DEFAULT_IMAGE_WIDTH
43
+ @image_height = DEFAULT_IMAGE_HEIGHT
44
+ @image_align = DEFAULT_IMAGE_ALIGN
45
+ @image_top = DEFAULT_IMAGE_TOP
46
+ @image_bottom = DEFAULT_IMAGE_BOTTOM
47
+ @image_left = DEFAULT_IMAGE_LEFT
48
+ @image_right = DEFAULT_IMAGE_RIGHT
49
+
50
+ super options, &block
51
+ end
52
+
53
+
54
+ #-------------------------------------------------------------
55
+ # Public Methods
56
+ #-------------------------------------------------------------
57
+
58
+ #=============== GETTERS ==============================
59
+
60
+ [:width, :height].each do |m|
61
+ define_method "formatted_#{ m }" do
62
+ value = send("image_#{ m }")
63
+ pixels_to_emus(value, image_ppi)
64
+ end
65
+ end
66
+
67
+ [:top, :bottom, :left, :right].each do |m|
68
+ define_method "formatted_#{ m }" do
69
+ value = send("image_#{ m }")
70
+ pixels_to_emus(value, 72)
71
+ end
72
+ end
73
+
74
+ def relationship_target
75
+ image_url || image_data
76
+ end
77
+
78
+
79
+ #=============== SETTERS ==============================
80
+
81
+ # integers
82
+ [:ppi, :width, :height, :top, :bottom, :left, :right].each do |m|
83
+ define_method "#{ m }" do |value|
84
+ instance_variable_set("@image_#{ m }", value.to_i)
85
+ end
86
+ end
87
+
88
+ # strings
89
+ [:data, :url].each do |m|
90
+ define_method "#{ m }" do |value|
91
+ instance_variable_set("@image_#{ m }", value.to_s)
92
+ end
93
+ end
94
+
95
+ # symbols
96
+ [:align].each do |m|
97
+ define_method "#{ m }" do |value|
98
+ instance_variable_set("@image_#{ m }", value.to_s.to_sym)
99
+ end
100
+ end
101
+
102
+
103
+ #=============== VALIDATION ==============================
104
+
105
+ def valid?
106
+ dims = [:ppi, :width, :height, :top, :bottom, :left, :right].map { |m| send("image_#{ m }") }
107
+ dims.all? { |d| d > 0 }
108
+ end
109
+
110
+
111
+
112
+ #-------------------------------------------------------------
113
+ # Private Methods
114
+ #-------------------------------------------------------------
115
+ private
116
+
117
+ def option_keys
118
+ [:url, :width, :height, :align, :top, :bottom, :left, :right]
119
+ end
120
+
121
+ def pixels_to_emus(value, ppi)
122
+ pixels = value.to_i
123
+ inches = pixels / ppi.to_f
124
+ emus_per_inch = 914400
125
+
126
+ emus = (inches * emus_per_inch).to_i
127
+ end
128
+
129
+ end
130
+
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,15 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class encapsulates the logic needed to store and manipulate
9
+ # line break data.
10
+ #
11
+ class LineBreakModel < BaseModel; end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,94 @@
1
+ require 'caracal/core/models/text_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class encapsulates the logic needed to store and manipulate
9
+ # link data.
10
+ #
11
+ class LinkModel < TextModel
12
+
13
+ #--------------------------------------------------
14
+ # Configuration
15
+ #--------------------------------------------------
16
+
17
+ # constants
18
+ const_set(:DEFAULT_LINK_COLOR, '1155cc')
19
+ const_set(:DEFAULT_LINK_UNDERLINE, true)
20
+
21
+ # readers (create aliases for superclass methods to conform
22
+ # to expected naming convention.)
23
+ attr_reader :link_href
24
+ attr_reader :link_internal
25
+ alias_method :link_content, :text_content
26
+ alias_method :link_font, :text_font
27
+ alias_method :link_color, :text_color
28
+ alias_method :link_size, :text_size
29
+ alias_method :link_bold, :text_bold
30
+ alias_method :link_italic, :text_italic
31
+ alias_method :link_underline, :text_underline
32
+ alias_method :link_bgcolor, :text_bgcolor
33
+ alias_method :link_highlight_color, :text_highlight_color
34
+ alias_method :link_vertical_align, :text_vertical_align
35
+
36
+ # initialization
37
+ def initialize(options={}, &block)
38
+ @text_color = DEFAULT_LINK_COLOR
39
+ @text_underline = DEFAULT_LINK_UNDERLINE
40
+
41
+ super options, &block
42
+ end
43
+
44
+
45
+ #--------------------------------------------------
46
+ # Public Instance Methods
47
+ #--------------------------------------------------
48
+
49
+ #========== SETTERS ===============================
50
+
51
+ # booleans
52
+ [:internal].each do |m|
53
+ define_method "#{ m }" do |value|
54
+ instance_variable_set("@link_#{ m }", !!value)
55
+ end
56
+ end
57
+
58
+ # strings
59
+ [:href].each do |m|
60
+ define_method "#{ m }" do |value|
61
+ instance_variable_set("@link_#{ m }", value.to_s)
62
+ end
63
+ end
64
+
65
+
66
+ #========== STATE HELPERS =========================
67
+
68
+ def external?
69
+ !link_internal
70
+ end
71
+
72
+
73
+ #========== VALIDATION ============================
74
+
75
+ def valid?
76
+ a = [:content, :href]
77
+ a.map { |m| send("link_#{ m }") }.compact.size == a.size
78
+ end
79
+
80
+
81
+ #--------------------------------------------------
82
+ # Private Instance Methods
83
+ #--------------------------------------------------
84
+ private
85
+
86
+ def option_keys
87
+ (super + [:internal, :href]).flatten
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+ end
94
+ end