reek 6.0.1 → 6.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.rubocop.yml +2 -20
  5. data/.rubocop_todo.yml +27 -20
  6. data/CHANGELOG.md +22 -0
  7. data/CONTRIBUTING.md +3 -0
  8. data/Dockerfile +1 -1
  9. data/Gemfile +6 -6
  10. data/README.md +1 -1
  11. data/bin/code_climate_reek +2 -3
  12. data/lib/reek.rb +1 -0
  13. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  14. data/lib/reek/ast/node.rb +1 -1
  15. data/lib/reek/cli/options.rb +1 -1
  16. data/lib/reek/configuration/app_configuration.rb +4 -3
  17. data/lib/reek/configuration/directory_directives.rb +2 -2
  18. data/lib/reek/configuration/excluded_paths.rb +2 -1
  19. data/lib/reek/context/code_context.rb +1 -1
  20. data/lib/reek/context/module_context.rb +3 -1
  21. data/lib/reek/context/refinement_context.rb +16 -0
  22. data/lib/reek/context_builder.rb +16 -2
  23. data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
  24. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
  25. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  26. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
  27. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
  28. data/lib/reek/smell_warning.rb +2 -3
  29. data/lib/reek/source/source_locator.rb +14 -13
  30. data/lib/reek/version.rb +1 -1
  31. data/reek.gemspec +14 -3
  32. metadata +29 -232
  33. data/.travis.yml +0 -36
  34. data/docs/API.md +0 -174
  35. data/docs/Attribute.md +0 -39
  36. data/docs/Basic-Smell-Options.md +0 -85
  37. data/docs/Boolean-Parameter.md +0 -54
  38. data/docs/Class-Variable.md +0 -40
  39. data/docs/Code-Smells.md +0 -39
  40. data/docs/Command-Line-Options.md +0 -119
  41. data/docs/Control-Couple.md +0 -26
  42. data/docs/Control-Parameter.md +0 -32
  43. data/docs/Data-Clump.md +0 -46
  44. data/docs/Duplicate-Method-Call.md +0 -264
  45. data/docs/Feature-Envy.md +0 -93
  46. data/docs/How-To-Write-New-Detectors.md +0 -132
  47. data/docs/How-reek-works-internally.md +0 -114
  48. data/docs/Instance-Variable-Assumption.md +0 -163
  49. data/docs/Irresponsible-Module.md +0 -47
  50. data/docs/Large-Class.md +0 -16
  51. data/docs/Long-Parameter-List.md +0 -39
  52. data/docs/Long-Yield-List.md +0 -37
  53. data/docs/Manual-Dispatch.md +0 -30
  54. data/docs/Missing-Safe-Method.md +0 -92
  55. data/docs/Module-Initialize.md +0 -62
  56. data/docs/Nested-Iterators.md +0 -59
  57. data/docs/Nil-Check.md +0 -47
  58. data/docs/RSpec-matchers.md +0 -129
  59. data/docs/Rake-Task.md +0 -66
  60. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  61. data/docs/Reek-Driven-Development.md +0 -46
  62. data/docs/Repeated-Conditional.md +0 -47
  63. data/docs/Simulated-Polymorphism.md +0 -16
  64. data/docs/Smell-Suppression.md +0 -96
  65. data/docs/Style-Guide.md +0 -19
  66. data/docs/Subclassed-From-Core-Class.md +0 -79
  67. data/docs/Too-Many-Constants.md +0 -37
  68. data/docs/Too-Many-Instance-Variables.md +0 -43
  69. data/docs/Too-Many-Methods.md +0 -56
  70. data/docs/Too-Many-Statements.md +0 -54
  71. data/docs/Uncommunicative-Method-Name.md +0 -94
  72. data/docs/Uncommunicative-Module-Name.md +0 -92
  73. data/docs/Uncommunicative-Name.md +0 -18
  74. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  75. data/docs/Uncommunicative-Variable-Name.md +0 -96
  76. data/docs/Unused-Parameters.md +0 -28
  77. data/docs/Unused-Private-Method.md +0 -101
  78. data/docs/Utility-Function.md +0 -56
  79. data/docs/Versioning-Policy.md +0 -7
  80. data/docs/YAML-Reports.md +0 -93
  81. data/docs/defaults.reek.yml +0 -129
  82. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  83. data/docs/templates/default/docstring/setup.rb +0 -37
  84. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  85. data/docs/yard_plugin.rb +0 -17
  86. data/features/command_line_interface/basic_usage.feature +0 -15
  87. data/features/command_line_interface/options.feature +0 -123
  88. data/features/command_line_interface/show_progress.feature +0 -33
  89. data/features/command_line_interface/smell_selection.feature +0 -15
  90. data/features/command_line_interface/smells_count.feature +0 -38
  91. data/features/command_line_interface/stdin.feature +0 -65
  92. data/features/configuration_files/accept_setting.feature +0 -87
  93. data/features/configuration_files/directory_specific_directives.feature +0 -274
  94. data/features/configuration_files/exclude_directives.feature +0 -35
  95. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  96. data/features/configuration_files/masking_smells.feature +0 -94
  97. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  98. data/features/configuration_files/reject_setting.feature +0 -89
  99. data/features/configuration_files/schema_validation.feature +0 -59
  100. data/features/configuration_files/show_configuration_file.feature +0 -44
  101. data/features/configuration_files/unused_private_method.feature +0 -68
  102. data/features/configuration_loading.feature +0 -91
  103. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  104. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  105. data/features/locales.feature +0 -32
  106. data/features/programmatic_access.feature +0 -41
  107. data/features/rake_task/rake_task.feature +0 -138
  108. data/features/reports/codeclimate.feature +0 -59
  109. data/features/reports/json.feature +0 -59
  110. data/features/reports/reports.feature +0 -219
  111. data/features/reports/yaml.feature +0 -52
  112. data/features/rspec_matcher.feature +0 -41
  113. data/features/samples.feature +0 -305
  114. data/features/step_definitions/.rubocop.yml +0 -5
  115. data/features/step_definitions/reek_steps.rb +0 -102
  116. data/features/step_definitions/sample_file_steps.rb +0 -63
  117. data/features/support/env.rb +0 -33
  118. data/features/todo_list.feature +0 -108
  119. data/samples/checkstyle.xml +0 -7
  120. data/samples/clean_source/clean.rb +0 -6
  121. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  122. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  123. data/samples/configuration/corrupt.reek +0 -1
  124. data/samples/configuration/empty.reek +0 -0
  125. data/samples/configuration/full_configuration.reek +0 -13
  126. data/samples/configuration/full_mask.reek +0 -6
  127. data/samples/configuration/home/home.reek.yml +0 -4
  128. data/samples/configuration/partial_mask.reek +0 -4
  129. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  130. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  131. data/samples/configuration/with_excluded_paths.reek +0 -5
  132. data/samples/no_config_file/.keep +0 -0
  133. data/samples/paths.rb +0 -5
  134. data/samples/smelly_source/inline.rb +0 -704
  135. data/samples/smelly_source/optparse.rb +0 -1788
  136. data/samples/smelly_source/redcloth.rb +0 -1130
  137. data/samples/smelly_source/ruby.rb +0 -368
  138. data/samples/smelly_source/smelly.rb +0 -7
  139. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  140. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  141. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  142. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  143. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  144. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  145. data/samples/source_with_non_ruby_files/gibberish +0 -1
  146. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  147. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  148. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -17
  149. data/spec/quality/documentation_spec.rb +0 -40
  150. data/spec/quality/reek_source_spec.rb +0 -11
  151. data/spec/reek/ast/node_spec.rb +0 -211
  152. data/spec/reek/ast/object_refs_spec.rb +0 -83
  153. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  154. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  155. data/spec/reek/cli/application_spec.rb +0 -168
  156. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  157. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  158. data/spec/reek/cli/options_spec.rb +0 -51
  159. data/spec/reek/cli/silencer_spec.rb +0 -28
  160. data/spec/reek/code_comment_spec.rb +0 -184
  161. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  162. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  163. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  164. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  165. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  166. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  167. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  168. data/spec/reek/context/code_context_spec.rb +0 -192
  169. data/spec/reek/context/ghost_context_spec.rb +0 -60
  170. data/spec/reek/context/method_context_spec.rb +0 -72
  171. data/spec/reek/context/module_context_spec.rb +0 -55
  172. data/spec/reek/context/root_context_spec.rb +0 -12
  173. data/spec/reek/context/statement_counter_spec.rb +0 -24
  174. data/spec/reek/context_builder_spec.rb +0 -457
  175. data/spec/reek/detector_repository_spec.rb +0 -22
  176. data/spec/reek/documentation_link_spec.rb +0 -20
  177. data/spec/reek/errors/base_error_spec.rb +0 -13
  178. data/spec/reek/examiner_spec.rb +0 -309
  179. data/spec/reek/logging_error_handler_spec.rb +0 -24
  180. data/spec/reek/rake/task_spec.rb +0 -56
  181. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  182. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  183. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  184. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  185. data/spec/reek/report/html_report_spec.rb +0 -19
  186. data/spec/reek/report/json_report_spec.rb +0 -58
  187. data/spec/reek/report/location_formatter_spec.rb +0 -32
  188. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  189. data/spec/reek/report/text_report_spec.rb +0 -89
  190. data/spec/reek/report/xml_report_spec.rb +0 -24
  191. data/spec/reek/report/yaml_report_spec.rb +0 -55
  192. data/spec/reek/report_spec.rb +0 -28
  193. data/spec/reek/smell_configuration_spec.rb +0 -56
  194. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  195. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  196. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  197. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  198. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  199. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  200. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  201. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  202. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  203. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  204. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  205. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  206. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  207. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  208. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  209. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  210. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  211. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  212. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  213. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  214. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  215. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  216. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  217. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  218. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  219. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  220. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  221. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  222. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  223. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  224. data/spec/reek/smell_warning_spec.rb +0 -137
  225. data/spec/reek/source/source_code_spec.rb +0 -79
  226. data/spec/reek/source/source_locator_spec.rb +0 -166
  227. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  228. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  229. data/spec/reek/spec/should_reek_spec.rb +0 -52
  230. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  231. data/spec/reek/tree_dresser_spec.rb +0 -46
  232. data/spec/spec_helper.rb +0 -110
  233. data/tasks/configuration.rake +0 -19
  234. data/tasks/console.rake +0 -5
  235. data/tasks/reek.rake +0 -6
  236. data/tasks/rubocop.rake +0 -11
  237. data/tasks/test.rake +0 -32
@@ -1,1130 +0,0 @@
1
- # vim:ts=4:sw=4:
2
- # = RedCloth - Textile and Markdown Hybrid for Ruby
3
- #
4
- # Homepage:: http://whytheluckystiff.net/ruby/redcloth/
5
- # Author:: why the lucky stiff (http://whytheluckystiff.net/)
6
- # Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.)
7
- # License:: BSD
8
- #
9
- # (see http://hobix.com/textile/ for a Textile Reference.)
10
- #
11
- # Based on (and also inspired by) both:
12
- #
13
- # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
14
- # Textism for PHP: http://www.textism.com/tools/textile/
15
- #
16
- #
17
-
18
- # = RedCloth
19
- #
20
- # RedCloth is a Ruby library for converting Textile and/or Markdown
21
- # into HTML. You can use either format, intermingled or separately.
22
- # You can also extend RedCloth to honor your own custom text stylings.
23
- #
24
- # RedCloth users are encouraged to use Textile if they are generating
25
- # HTML and to use Markdown if others will be viewing the plain text.
26
- #
27
- # == What is Textile?
28
- #
29
- # Textile is a simple formatting style for text
30
- # documents, loosely based on some HTML conventions.
31
- #
32
- # == Sample Textile Text
33
- #
34
- # h2. This is a title
35
- #
36
- # h3. This is a subhead
37
- #
38
- # This is a bit of paragraph.
39
- #
40
- # bq. This is a blockquote.
41
- #
42
- # = Writing Textile
43
- #
44
- # A Textile document consists of paragraphs. Paragraphs
45
- # can be specially formatted by adding a small instruction
46
- # to the beginning of the paragraph.
47
- #
48
- # h[n]. Header of size [n].
49
- # bq. Blockquote.
50
- # # Numeric list.
51
- # * Bulleted list.
52
- #
53
- # == Quick Phrase Modifiers
54
- #
55
- # Quick phrase modifiers are also included, to allow formatting
56
- # of small portions of text within a paragraph.
57
- #
58
- # \_emphasis\_
59
- # \_\_italicized\_\_
60
- # \*strong\*
61
- # \*\*bold\*\*
62
- # ??citation??
63
- # -deleted text-
64
- # +inserted text+
65
- # ^superscript^
66
- # ~subscript~
67
- # @code@
68
- # %(classname)span%
69
- #
70
- # ==notextile== (leave text alone)
71
- #
72
- # == Links
73
- #
74
- # To make a hypertext link, put the link text in "quotation
75
- # marks" followed immediately by a colon and the URL of the link.
76
- #
77
- # Optional: text in (parentheses) following the link text,
78
- # but before the closing quotation mark, will become a Title
79
- # attribute for the link, visible as a tool tip when a cursor is above it.
80
- #
81
- # Example:
82
- #
83
- # "This is a link (This is a title) ":http://www.textism.com
84
- #
85
- # Will become:
86
- #
87
- # <a href="http://www.textism.com" title="This is a title">This is a link</a>
88
- #
89
- # == Images
90
- #
91
- # To insert an image, put the URL for the image inside exclamation marks.
92
- #
93
- # Optional: text that immediately follows the URL in (parentheses) will
94
- # be used as the Alt text for the image. Images on the web should always
95
- # have descriptive Alt text for the benefit of readers using non-graphical
96
- # browsers.
97
- #
98
- # Optional: place a colon followed by a URL immediately after the
99
- # closing ! to make the image into a link.
100
- #
101
- # Example:
102
- #
103
- # !http://www.textism.com/common/textist.gif(Textist)!
104
- #
105
- # Will become:
106
- #
107
- # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
108
- #
109
- # With a link:
110
- #
111
- # !/common/textist.gif(Textist)!:http://textism.com
112
- #
113
- # Will become:
114
- #
115
- # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
116
- #
117
- # == Defining Acronyms
118
- #
119
- # HTML allows authors to define acronyms via the tag. The definition appears as a
120
- # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
121
- # this should be used at least once for each acronym in documents where they appear.
122
- #
123
- # To quickly define an acronym in Textile, place the full text in (parentheses)
124
- # immediately following the acronym.
125
- #
126
- # Example:
127
- #
128
- # ACLU(American Civil Liberties Union)
129
- #
130
- # Will become:
131
- #
132
- # <acronym title="American Civil Liberties Union">ACLU</acronym>
133
- #
134
- # == Adding Tables
135
- #
136
- # In Textile, simple tables can be added by seperating each column by
137
- # a pipe.
138
- #
139
- # |a|simple|table|row|
140
- # |And|Another|table|row|
141
- #
142
- # Attributes are defined by style definitions in parentheses.
143
- #
144
- # table(border:1px solid black).
145
- # (background:#ddd;color:red). |{}| | | |
146
- #
147
- # == Using RedCloth
148
- #
149
- # RedCloth is simply an extension of the String class, which can handle
150
- # Textile formatting. Use it like a String and output HTML with its
151
- # RedCloth#to_html method.
152
- #
153
- # doc = RedCloth.new "
154
- #
155
- # h2. Test document
156
- #
157
- # Just a simple test."
158
- #
159
- # puts doc.to_html
160
- #
161
- # By default, RedCloth uses both Textile and Markdown formatting, with
162
- # Textile formatting taking precedence. If you want to turn off Markdown
163
- # formatting, to boost speed and limit the processor:
164
- #
165
- # class RedCloth::Textile.new( str )
166
-
167
- class RedCloth < String
168
-
169
- VERSION = '3.0.4'
170
- DEFAULT_RULES = [:textile, :markdown]
171
-
172
- #
173
- # Two accessor for setting security restrictions.
174
- #
175
- # This is a nice thing if you're using RedCloth for
176
- # formatting in public places (e.g. Wikis) where you
177
- # don't want users to abuse HTML for bad things.
178
- #
179
- # If +:filter_html+ is set, HTML which wasn't
180
- # created by the Textile processor will be escaped.
181
- #
182
- # If +:filter_styles+ is set, it will also disable
183
- # the style markup specifier. ('{color: red}')
184
- #
185
- attr_accessor :filter_html, :filter_styles
186
-
187
- #
188
- # Accessor for toggling hard breaks.
189
- #
190
- # If +:hard_breaks+ is set, single newlines will
191
- # be converted to HTML break tags. This is the
192
- # default behavior for traditional RedCloth.
193
- #
194
- attr_accessor :hard_breaks
195
-
196
- # Accessor for toggling lite mode.
197
- #
198
- # In lite mode, block-level rules are ignored. This means
199
- # that tables, paragraphs, lists, and such aren't available.
200
- # Only the inline markup for bold, italics, entities and so on.
201
- #
202
- # r = RedCloth.new( "And then? She *fell*!", [:lite_mode] )
203
- # r.to_html
204
- # #=> "And then? She <strong>fell</strong>!"
205
- #
206
- attr_accessor :lite_mode
207
-
208
- #
209
- # Accessor for toggling span caps.
210
- #
211
- # Textile places `span' tags around capitalized
212
- # words by default, but this wreaks havoc on Wikis.
213
- # If +:no_span_caps+ is set, this will be
214
- # suppressed.
215
- #
216
- attr_accessor :no_span_caps
217
-
218
- #
219
- # Establishes the markup predence. Available rules include:
220
- #
221
- # == Textile Rules
222
- #
223
- # The following textile rules can be set individually. Or add the complete
224
- # set of rules with the single :textile rule, which supplies the rule set in
225
- # the following precedence:
226
- #
227
- # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
228
- # block_textile_table:: Textile table block structures
229
- # block_textile_lists:: Textile list structures
230
- # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
231
- # inline_textile_image:: Textile inline images
232
- # inline_textile_link:: Textile inline links
233
- # inline_textile_span:: Textile inline spans
234
- # glyphs_textile:: Textile entities (such as em-dashes and smart quotes)
235
- #
236
- # == Markdown
237
- #
238
- # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/)
239
- # block_markdown_setext:: Markdown setext headers
240
- # block_markdown_atx:: Markdown atx headers
241
- # block_markdown_rule:: Markdown horizontal rules
242
- # block_markdown_bq:: Markdown blockquotes
243
- # block_markdown_lists:: Markdown lists
244
- # inline_markdown_link:: Markdown links
245
- attr_accessor :rules
246
-
247
- # Returns a new RedCloth object, based on _string_ and
248
- # enforcing all the included _restrictions_.
249
- #
250
- # r = RedCloth.new( "h1. A <b>bold</b> man", [:filter_html] )
251
- # r.to_html
252
- # #=>"<h1>A &lt;b&gt;bold&lt;/b&gt; man</h1>"
253
- #
254
- def initialize( string, restrictions = [] )
255
- restrictions.each { |r| method( "#{ r }=" ).call( true ) }
256
- super( string )
257
- end
258
-
259
- #
260
- # Generates HTML from the Textile contents.
261
- #
262
- # r = RedCloth.new( "And then? She *fell*!" )
263
- # r.to_html( true )
264
- # #=>"And then? She <strong>fell</strong>!"
265
- #
266
- def to_html( *rules )
267
- rules = DEFAULT_RULES if rules.empty?
268
- # make our working copy
269
- text = self.dup
270
-
271
- @urlrefs = {}
272
- @shelf = []
273
- textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
274
- :block_textile_prefix, :inline_textile_image, :inline_textile_link,
275
- :inline_textile_code, :inline_textile_span, :glyphs_textile]
276
- markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
277
- :block_markdown_bq, :block_markdown_lists,
278
- :inline_markdown_reflink, :inline_markdown_link]
279
- @rules = rules.collect do |rule|
280
- case rule
281
- when :markdown
282
- markdown_rules
283
- when :textile
284
- textile_rules
285
- else
286
- rule
287
- end
288
- end.flatten
289
-
290
- # standard clean up
291
- incoming_entities text
292
- clean_white_space text
293
-
294
- # start processor
295
- @pre_list = []
296
- rip_offtags text
297
- no_textile text
298
- hard_break text
299
- unless @lite_mode
300
- refs text
301
- blocks text
302
- end
303
- inline text
304
- smooth_offtags text
305
-
306
- retrieve text
307
-
308
- text.gsub!( /<\/?notextile>/, '' )
309
- text.gsub!( /x%x%/, '&#38;' )
310
- clean_html text if filter_html
311
- text.strip!
312
- text
313
-
314
- end
315
-
316
- #######
317
- private
318
- #######
319
- #
320
- # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
321
- # (from PyTextile)
322
- #
323
- TEXTILE_TAGS =
324
-
325
- [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
326
- [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
327
- [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
328
- [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
329
- [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
330
-
331
- collect! do |a, b|
332
- [a.chr, ( b.zero? and "" or "&#{ b };" )]
333
- end
334
-
335
- #
336
- # Regular expressions to convert to HTML.
337
- #
338
- A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
339
- A_VLGN = /[\-^~]/
340
- C_CLAS = '(?:\([^)]+\))'
341
- C_LNGE = '(?:\[[^\]]+\])'
342
- C_STYL = '(?:\{[^}]+\})'
343
- S_CSPN = '(?:\\\\\d+)'
344
- S_RSPN = '(?:/\d+)'
345
- A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
346
- S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
347
- C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
348
- # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
349
- PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
350
- PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' )
351
- PUNCT_Q = Regexp::quote( '*-_+^~%' )
352
- HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)'
353
-
354
- # Text markup tags, don't conflict with block tags
355
- SIMPLE_HTML_TAGS = [
356
- 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',
357
- 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',
358
- 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
359
- ]
360
-
361
- QTAGS = [
362
- ['**', 'b'],
363
- ['*', 'strong'],
364
- ['??', 'cite', :limit],
365
- ['-', 'del', :limit],
366
- ['__', 'i'],
367
- ['_', 'em', :limit],
368
- ['%', 'span', :limit],
369
- ['+', 'ins', :limit],
370
- ['^', 'sup'],
371
- ['~', 'sub']
372
- ]
373
- QTAGS.collect! do |rc, ht, rtype|
374
- rcq = Regexp::quote rc
375
- re =
376
- case rtype
377
- when :limit
378
- /(\W)
379
- (#{rcq})
380
- (#{C})
381
- (?::(\S+?))?
382
- (\S.*?\S|\S)
383
- #{rcq}
384
- (?=\W)/x
385
- else
386
- /(#{rcq})
387
- (#{C})
388
- (?::(\S+))?
389
- (\S.*?\S|\S)
390
- #{rcq}/xm
391
- end
392
- [rc, ht, re, rtype]
393
- end
394
-
395
- # Elements to handle
396
- GLYPHS = [
397
- # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
398
- [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
399
- [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
400
- [ /\'/, '&#8216;' ], # single opening
401
- [ /</, '&lt;' ], # less-than
402
- [ />/, '&gt;' ], # greater-than
403
- # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
404
- [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
405
- [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
406
- [ /"/, '&#8220;' ], # double opening
407
- [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
408
- [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
409
- [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
410
- [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
411
- [ /\s->\s/, ' &rarr; ' ], # right arrow
412
- [ /\s-\s/, ' &#8211; ' ], # en dash
413
- [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
414
- [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
415
- [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
416
- [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
417
- ]
418
-
419
- H_ALGN_VALS = {
420
- '<' => 'left',
421
- '=' => 'center',
422
- '>' => 'right',
423
- '<>' => 'justify'
424
- }
425
-
426
- V_ALGN_VALS = {
427
- '^' => 'top',
428
- '-' => 'middle',
429
- '~' => 'bottom'
430
- }
431
-
432
- #
433
- # Flexible HTML escaping
434
- #
435
- def htmlesc( str, mode )
436
- str.gsub!( '&', '&amp;' )
437
- str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
438
- str.gsub!( "'", '&#039;' ) if mode == :Quotes
439
- str.gsub!( '<', '&lt;')
440
- str.gsub!( '>', '&gt;')
441
- end
442
-
443
- # Search and replace for Textile glyphs (quotes, dashes, other symbols)
444
- def pgl( text )
445
- GLYPHS.each do |re, resub, tog|
446
- next if tog and method( tog ).call
447
- text.gsub! re, resub
448
- end
449
- end
450
-
451
- # Parses Textile attribute lists and builds an HTML attribute string
452
- def pba( text_in, element = "" )
453
-
454
- return '' unless text_in
455
-
456
- style = []
457
- text = text_in.dup
458
- if element == 'td'
459
- colspan = $1 if text =~ /\\(\d+)/
460
- rowspan = $1 if text =~ /\/(\d+)/
461
- style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
462
- end
463
-
464
- style << "#{ $1 };" if not filter_styles and
465
- text.sub!( /\{([^}]*)\}/, '' )
466
-
467
- lang = $1 if
468
- text.sub!( /\[([^)]+?)\]/, '' )
469
-
470
- cls = $1 if
471
- text.sub!( /\(([^()]+?)\)/, '' )
472
-
473
- style << "padding-left:#{ $1.length }em;" if
474
- text.sub!( /([(]+)/, '' )
475
-
476
- style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
477
-
478
- style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
479
-
480
- cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
481
-
482
- atts = ''
483
- atts << " style=\"#{ style.join }\"" unless style.empty?
484
- atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
485
- atts << " lang=\"#{ lang }\"" if lang
486
- atts << " id=\"#{ id }\"" if id
487
- atts << " colspan=\"#{ colspan }\"" if colspan
488
- atts << " rowspan=\"#{ rowspan }\"" if rowspan
489
-
490
- atts
491
- end
492
-
493
- TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
494
-
495
- # Parses a Textile table block, building HTML from the result.
496
- def block_textile_table( text )
497
- text.gsub!( TABLE_RE ) do |matches|
498
-
499
- tatts, fullrow = $~[1..2]
500
- tatts = pba( tatts, 'table' )
501
- tatts = shelve( tatts ) if tatts
502
- rows = []
503
-
504
- fullrow.
505
- split( /\|$/m ).
506
- delete_if { |x| x.empty? }.
507
- each do |row|
508
-
509
- ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
510
-
511
- cells = []
512
- row.split( '|' ).each do |cell|
513
- ctyp = 'd'
514
- ctyp = 'h' if cell =~ /^_/
515
-
516
- catts = ''
517
- catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/
518
-
519
- unless cell.strip.empty?
520
- catts = shelve( catts ) if catts
521
- cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
522
- end
523
- end
524
- ratts = shelve( ratts ) if ratts
525
- rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
526
- end
527
- "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
528
- end
529
- end
530
-
531
- LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m
532
- LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m
533
-
534
- # Parses Textile lists and generates HTML
535
- def block_textile_lists( text )
536
- text.gsub!( LISTS_RE ) do |match|
537
- lines = match.split( /\n/ )
538
- last_line = -1
539
- depth = []
540
- lines.each_with_index do |line, line_id|
541
- if line =~ LISTS_CONTENT_RE
542
- tl,atts,content = $~[1..3]
543
- if depth.last
544
- if depth.last.length > tl.length
545
- (depth.length - 1).downto(0) do |i|
546
- break if depth[i].length == tl.length
547
- lines[line_id - 1] << "</li>\n\t</#{ lT( depth[i] ) }l>\n\t"
548
- depth.pop
549
- end
550
- end
551
- if depth.last and depth.last.length == tl.length
552
- lines[line_id - 1] << '</li>'
553
- end
554
- end
555
- unless depth.last == tl
556
- depth << tl
557
- atts = pba( atts )
558
- atts = shelve( atts ) if atts
559
- lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t<li>#{ content }"
560
- else
561
- lines[line_id] = "\t\t<li>#{ content }"
562
- end
563
- last_line = line_id
564
-
565
- else
566
- last_line = line_id
567
- end
568
- if line_id - last_line > 1 or line_id == lines.length - 1
569
- depth.delete_if do |v|
570
- lines[last_line] << "</li>\n\t</#{ lT( v ) }l>"
571
- end
572
- end
573
- end
574
- lines.join( "\n" )
575
- end
576
- end
577
-
578
- CODE_RE = /(\W)
579
- @
580
- (?:\|(\w+?)\|)?
581
- (.+?)
582
- @
583
- (?=\W)/x
584
-
585
- def inline_textile_code( text )
586
- text.gsub!( CODE_RE ) do |m|
587
- before,lang,code,after = $~[1..4]
588
- lang = " lang=\"#{ lang }\"" if lang
589
- rip_offtags( "#{ before }<code#{ lang }>#{ code }</code>#{ after }" )
590
- end
591
- end
592
-
593
- def lT( text )
594
- text =~ /\#$/ ? 'o' : 'u'
595
- end
596
-
597
- def hard_break( text )
598
- text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
599
- end
600
-
601
- BLOCKS_GROUP_RE = /\n{2,}(?! )/m
602
-
603
- def blocks( text, deep_code = false )
604
- text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk|
605
- plain = blk !~ /\A[#*> ]/
606
-
607
- # skip blocks that are complex HTML
608
- if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1
609
- blk
610
- else
611
- # search for indentation levels
612
- blk.strip!
613
- if blk.empty?
614
- blk
615
- else
616
- code_blk = nil
617
- blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk|
618
- flush_left iblk
619
- blocks iblk, plain
620
- iblk.gsub( /^(\S)/, "\t\\1" )
621
- if plain
622
- code_blk = iblk; ""
623
- else
624
- iblk
625
- end
626
- end
627
-
628
- block_applied = 0
629
- @rules.each do |rule_name|
630
- block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )
631
- end
632
- if block_applied.zero?
633
- if deep_code
634
- blk = "\t<pre><code>#{ blk }</code></pre>"
635
- else
636
- blk = "\t<p>#{ blk }</p>"
637
- end
638
- end
639
- # hard_break blk
640
- blk + "\n#{ code_blk }"
641
- end
642
- end
643
-
644
- end.join( "\n\n" ) )
645
- end
646
-
647
- def textile_bq( tag, atts, cite, content )
648
- cite, cite_title = check_refs( cite )
649
- cite = " cite=\"#{ cite }\"" if cite
650
- atts = shelve( atts ) if atts
651
- "\t<blockquote#{ cite }>\n\t\t<p#{ atts }>#{ content }</p>\n\t</blockquote>"
652
- end
653
-
654
- def textile_p( tag, atts, cite, content )
655
- atts = shelve( atts ) if atts
656
- "\t<#{ tag }#{ atts }>#{ content }</#{ tag }>"
657
- end
658
-
659
- alias textile_h1 textile_p
660
- alias textile_h2 textile_p
661
- alias textile_h3 textile_p
662
- alias textile_h4 textile_p
663
- alias textile_h5 textile_p
664
- alias textile_h6 textile_p
665
-
666
- def textile_fn_( tag, num, atts, cite, content )
667
- atts << " id=\"fn#{ num }\""
668
- content = "<sup>#{ num }</sup> #{ content }"
669
- atts = shelve( atts ) if atts
670
- "\t<p#{ atts }>#{ content }</p>"
671
- end
672
-
673
- BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m
674
-
675
- def block_textile_prefix( text )
676
- if text =~ BLOCK_RE
677
- tag,tagpre,num,atts,cite,content = $~[1..6]
678
- atts = pba( atts )
679
-
680
- # pass to prefix handler
681
- if respond_to? "textile_#{ tag }", true
682
- text.gsub!( $&, method( "textile_#{ tag }" ).call( tag, atts, cite, content ) )
683
- elsif respond_to? "textile_#{ tagpre }_", true
684
- text.gsub!( $&, method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) )
685
- end
686
- end
687
- end
688
-
689
- SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m
690
- def block_markdown_setext( text )
691
- if text =~ SETEXT_RE
692
- tag = if $2 == "="; "h1"; else; "h2"; end
693
- blk, cont = "<#{ tag }>#{ $1 }</#{ tag }>", $'
694
- blocks cont
695
- text.replace( blk + cont )
696
- end
697
- end
698
-
699
- ATX_RE = /\A(\#{1,6}) # $1 = string of #'s
700
- [ ]*
701
- (.+?) # $2 = Header text
702
- [ ]*
703
- \#* # optional closing #'s (not counted)
704
- $/x
705
- def block_markdown_atx( text )
706
- if text =~ ATX_RE
707
- tag = "h#{ $1.length }"
708
- blk, cont = "<#{ tag }>#{ $2 }</#{ tag }>\n\n", $'
709
- blocks cont
710
- text.replace( blk + cont )
711
- end
712
- end
713
-
714
- MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m
715
-
716
- def block_markdown_bq( text )
717
- text.gsub!( MARKDOWN_BQ_RE ) do |blk|
718
- blk.gsub!( /^ *> ?/, '' )
719
- flush_left blk
720
- blocks blk
721
- blk.gsub!( /^(\S)/, "\t\\1" )
722
- "<blockquote>\n#{ blk }\n</blockquote>\n\n"
723
- end
724
- end
725
-
726
- MARKDOWN_RULE_RE = /^(#{
727
- ['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )
728
- })$/
729
-
730
- def block_markdown_rule( text )
731
- text.gsub!( MARKDOWN_RULE_RE ) do |blk|
732
- "<hr />"
733
- end
734
- end
735
-
736
- # XXX TODO XXX
737
- def block_markdown_lists( text )
738
- end
739
-
740
- def inline_textile_span( text )
741
- QTAGS.each do |qtag_rc, ht, qtag_re, rtype|
742
- text.gsub!( qtag_re ) do |m|
743
-
744
- case rtype
745
- when :limit
746
- sta,qtag,atts,cite,content = $~[1..5]
747
- else
748
- qtag,atts,cite,content = $~[1..4]
749
- sta = ''
750
- end
751
- atts = pba( atts )
752
- atts << " cite=\"#{ cite }\"" if cite
753
- atts = shelve( atts ) if atts
754
-
755
- "#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>"
756
-
757
- end
758
- end
759
- end
760
-
761
- LINK_RE = /
762
- ([\s\[{(]|[#{PUNCT}])? # $pre
763
- " # start
764
- (#{C}) # $atts
765
- ([^"]+?) # $text
766
- \s?
767
- (?:\(([^)]+?)\)(?="))? # $title
768
- ":
769
- (\S+?) # $url
770
- (\/)? # $slash
771
- ([^\w\/;]*?) # $post
772
- (?=<|\s|$)
773
- /x
774
-
775
- def inline_textile_link( text )
776
- text.gsub!( LINK_RE ) do |m|
777
- pre,atts,text,title,url,slash,post = $~[1..7]
778
-
779
- url, url_title = check_refs( url )
780
- title ||= url_title
781
-
782
- atts = pba( atts )
783
- atts = " href=\"#{ url }#{ slash }\"#{ atts }"
784
- atts << " title=\"#{ title }\"" if title
785
- atts = shelve( atts ) if atts
786
-
787
- "#{ pre }<a#{ atts }>#{ text }</a>#{ post }"
788
- end
789
- end
790
-
791
- MARKDOWN_REFLINK_RE = /
792
- \[([^\[\]]+)\] # $text
793
- [ ]? # opt. space
794
- (?:\n[ ]*)? # one optional newline followed by spaces
795
- \[(.*?)\] # $id
796
- /x
797
-
798
- def inline_markdown_reflink( text )
799
- text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
800
- text, id = $~[1..2]
801
-
802
- if id.empty?
803
- url, title = check_refs( text )
804
- else
805
- url, title = check_refs( id )
806
- end
807
-
808
- atts = " href=\"#{ url }\""
809
- atts << " title=\"#{ title }\"" if title
810
- atts = shelve( atts )
811
-
812
- "<a#{ atts }>#{ text }</a>"
813
- end
814
- end
815
-
816
- MARKDOWN_LINK_RE = /
817
- \[([^\[\]]+)\] # $text
818
- \( # open paren
819
- [ \t]* # opt space
820
- <?(.+?)>? # $href
821
- [ \t]* # opt space
822
- (?: # whole title
823
- (['"]) # $quote
824
- (.*?) # $title
825
- \3 # matching quote
826
- )? # title is optional
827
- \)
828
- /x
829
-
830
- def inline_markdown_link( text )
831
- text.gsub!( MARKDOWN_LINK_RE ) do |m|
832
- text, url, quote, title = $~[1..4]
833
-
834
- atts = " href=\"#{ url }\""
835
- atts << " title=\"#{ title }\"" if title
836
- atts = shelve( atts )
837
-
838
- "<a#{ atts }>#{ text }</a>"
839
- end
840
- end
841
-
842
- TEXTILE_REFS_RE = /(^ *)\[([^\n]+?)\](#{HYPERLINK})(?=\s|$)/
843
- MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+<?(#{HYPERLINK})>?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m
844
-
845
- def refs( text )
846
- @rules.each do |rule_name|
847
- method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/
848
- end
849
- end
850
-
851
- def refs_textile( text )
852
- text.gsub!( TEXTILE_REFS_RE ) do |m|
853
- flag, url = $~[2..3]
854
- @urlrefs[flag.downcase] = [url, nil]
855
- nil
856
- end
857
- end
858
-
859
- def refs_markdown( text )
860
- text.gsub!( MARKDOWN_REFS_RE ) do |m|
861
- flag, url = $~[2..3]
862
- title = $~[6]
863
- @urlrefs[flag.downcase] = [url, title]
864
- nil
865
- end
866
- end
867
-
868
- def check_refs( text )
869
- ret = @urlrefs[text.downcase] if text
870
- ret || [text, nil]
871
- end
872
-
873
- IMAGE_RE = /
874
- (<p>|.|^) # start of line?
875
- \! # opening
876
- (\<|\=|\>)? # optional alignment atts
877
- (#{C}) # optional style,class atts
878
- (?:\. )? # optional dot-space
879
- ([^\s(!]+?) # presume this is the src
880
- \s? # optional space
881
- (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
882
- \! # closing
883
- (?::#{ HYPERLINK })? # optional href
884
- /x
885
-
886
- def inline_textile_image( text )
887
- text.gsub!( IMAGE_RE ) do |m|
888
- stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
889
- atts = pba( atts )
890
- atts = " src=\"#{ url }\"#{ atts }"
891
- atts << " title=\"#{ title }\"" if title
892
- atts << " alt=\"#{ title }\""
893
- # size = @getimagesize($url);
894
- # if($size) $atts.= " $size[3]";
895
-
896
- href, alt_title = check_refs( href ) if href
897
- url, url_title = check_refs( url )
898
-
899
- out = ''
900
- out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
901
- out << "<img#{ shelve( atts ) } />"
902
- out << "</a>#{ href_a1 }#{ href_a2 }" if href
903
-
904
- if algn
905
- algn = h_align( algn )
906
- if stln == "<p>"
907
- out = "<p style=\"float:#{ algn }\">#{ out }"
908
- else
909
- out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
910
- end
911
- else
912
- out = stln + out
913
- end
914
-
915
- out
916
- end
917
- end
918
-
919
- def shelve( val )
920
- @shelf << val
921
- " :redsh##{ @shelf.length }:"
922
- end
923
-
924
- def retrieve( text )
925
- @shelf.each_with_index do |r, i|
926
- text.gsub!( " :redsh##{ i + 1 }:", r )
927
- end
928
- end
929
-
930
- def incoming_entities( text )
931
- ## turn any incoming ampersands into a dummy character for now.
932
- ## This uses a negative lookahead for alphanumerics followed by a semicolon,
933
- ## implying an incoming html entity, to be skipped
934
-
935
- text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
936
- end
937
-
938
- def no_textile( text )
939
- text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/,
940
- '\1<notextile>\2</notextile>\3' )
941
- text.gsub!( /^ *==([^=]+.*?)==/m,
942
- '\1<notextile>\2</notextile>\3' )
943
- end
944
-
945
- def clean_white_space( text )
946
- # normalize line breaks
947
- text.gsub!( /\r\n/, "\n" )
948
- text.gsub!( /\r/, "\n" )
949
- text.gsub!( /\t/, ' ' )
950
- text.gsub!( /^ +$/, '' )
951
- text.gsub!( /\n{3,}/, "\n\n" )
952
- text.gsub!( /"$/, "\" " )
953
-
954
- # if entire document is indented, flush
955
- # to the left side
956
- flush_left text
957
- end
958
-
959
- def flush_left( text )
960
- indt = 0
961
- if text =~ /^ /
962
- while text !~ /^ {#{indt}}\S/
963
- indt += 1
964
- end unless text.empty?
965
- if indt.nonzero?
966
- text.gsub!( /^ {#{indt}}/, '' )
967
- end
968
- end
969
- end
970
-
971
- def footnote_ref( text )
972
- text.gsub!( /\b\[([0-9]+?)\](\s)?/,
973
- '<sup><a href="#fn\1">\1</a></sup>\2' )
974
- end
975
-
976
- OFFTAGS = /(code|pre|kbd|notextile)/
977
- OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }|\Z)/mi
978
- OFFTAG_OPEN = /<#{ OFFTAGS }/
979
- OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
980
- HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
981
- ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m
982
-
983
- def glyphs_textile( text, level = 0 )
984
- if text !~ HASTAG_MATCH
985
- pgl text
986
- footnote_ref text
987
- else
988
- codepre = 0
989
- text.gsub!( ALLTAG_MATCH ) do |line|
990
- ## matches are off if we're between <code>, <pre> etc.
991
- if $1
992
- if line =~ OFFTAG_OPEN
993
- codepre += 1
994
- elsif line =~ OFFTAG_CLOSE
995
- codepre -= 1
996
- codepre = 0 if codepre < 0
997
- end
998
- elsif codepre.zero?
999
- glyphs_textile( line, level + 1 )
1000
- else
1001
- htmlesc( line, :NoQuotes )
1002
- end
1003
- # p [level, codepre, line]
1004
-
1005
- line
1006
- end
1007
- end
1008
- end
1009
-
1010
- def rip_offtags( text )
1011
- if text =~ /<.*>/
1012
- ## strip and encode <pre> content
1013
- codepre, used_offtags = 0, {}
1014
- text.gsub!( OFFTAG_MATCH ) do |line|
1015
- if $3
1016
- offtag, aftertag = $4, $5
1017
- codepre += 1
1018
- used_offtags[offtag] = true
1019
- if codepre - used_offtags.length > 0
1020
- htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1021
- @pre_list.last << line
1022
- line = ""
1023
- else
1024
- htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
1025
- line = "<redpre##{ @pre_list.length }>"
1026
- @pre_list << "#{ $3 }#{ aftertag }"
1027
- end
1028
- elsif $1 and codepre > 0
1029
- if codepre - used_offtags.length > 0
1030
- htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1031
- @pre_list.last << line
1032
- line = ""
1033
- end
1034
- codepre -= 1 unless codepre.zero?
1035
- used_offtags = {} if codepre.zero?
1036
- end
1037
- line
1038
- end
1039
- end
1040
- text
1041
- end
1042
-
1043
- def smooth_offtags( text )
1044
- unless @pre_list.empty?
1045
- ## replace <pre> content
1046
- text.gsub!( /<redpre#(\d+)>/ ) { @pre_list[$1.to_i] }
1047
- end
1048
- end
1049
-
1050
- def inline( text )
1051
- [/^inline_/, /^glyphs_/].each do |meth_re|
1052
- @rules.each do |rule_name|
1053
- method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
1054
- end
1055
- end
1056
- end
1057
-
1058
- def h_align( text )
1059
- H_ALGN_VALS[text]
1060
- end
1061
-
1062
- def v_align( text )
1063
- V_ALGN_VALS[text]
1064
- end
1065
-
1066
- def textile_popup_help( name, windowW, windowH )
1067
- ' <a target="_blank" href="http://hobix.com/textile/#' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
1068
- end
1069
-
1070
- # HTML cleansing stuff
1071
- BASIC_TAGS = {
1072
- 'a' => ['href', 'title'],
1073
- 'img' => ['src', 'alt', 'title'],
1074
- 'br' => [],
1075
- 'i' => nil,
1076
- 'u' => nil,
1077
- 'b' => nil,
1078
- 'pre' => nil,
1079
- 'kbd' => nil,
1080
- 'code' => ['lang'],
1081
- 'cite' => nil,
1082
- 'strong' => nil,
1083
- 'em' => nil,
1084
- 'ins' => nil,
1085
- 'sup' => nil,
1086
- 'sub' => nil,
1087
- 'del' => nil,
1088
- 'table' => nil,
1089
- 'tr' => nil,
1090
- 'td' => ['colspan', 'rowspan'],
1091
- 'th' => nil,
1092
- 'ol' => nil,
1093
- 'ul' => nil,
1094
- 'li' => nil,
1095
- 'p' => nil,
1096
- 'h1' => nil,
1097
- 'h2' => nil,
1098
- 'h3' => nil,
1099
- 'h4' => nil,
1100
- 'h5' => nil,
1101
- 'h6' => nil,
1102
- 'blockquote' => ['cite']
1103
- }
1104
-
1105
- def clean_html( text, tags = BASIC_TAGS )
1106
- text.gsub!( /<!\[CDATA\[/, '' )
1107
- text.gsub!( /<(\/*)(\w+)([^>]*)>/ ) do
1108
- raw = $~
1109
- tag = raw[2].downcase
1110
- if tags.has_key? tag
1111
- pcs = [tag]
1112
- tags[tag].each do |prop|
1113
- ['"', "'", ''].each do |q|
1114
- q2 = ( q != '' ? q : '\s' )
1115
- if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
1116
- attrv = $1
1117
- next if prop == 'src' and attrv =~ %r{^(?!http)\w+:}
1118
- pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\""
1119
- break
1120
- end
1121
- end
1122
- end if tags[tag]
1123
- "<#{raw[1]}#{pcs.join " "}>"
1124
- else
1125
- " "
1126
- end
1127
- end
1128
- end
1129
- end
1130
-