PageRenderTime 41ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 2ms

/text/src/test/resources/examples/ruby/rails.in.rb

https://github.com/rimolive/core
Ruby | 15466 lines | 11031 code | 1665 blank | 2770 comment | 670 complexity | cc3b4273ae9f93be89092edb70074a1b MD5 | raw file
Possible License(s): EPL-1.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. require 'rbconfig'
  2. require 'find'
  3. require 'ftools'
  4. include Config
  5. # this was adapted from rdoc's install.rb by way of Log4r
  6. $sitedir = CONFIG["sitelibdir"]
  7. unless $sitedir
  8. version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
  9. $libdir = File.join(CONFIG["libdir"], "ruby", version)
  10. $sitedir = $:.find {|x| x =~ /site_ruby/ }
  11. if !$sitedir
  12. $sitedir = File.join($libdir, "site_ruby")
  13. elsif $sitedir !~ Regexp.quote(version)
  14. $sitedir = File.join($sitedir, version)
  15. end
  16. end
  17. # the acual gruntwork
  18. Dir.chdir("lib")
  19. Find.find("action_mailer", "action_mailer.rb") { |f|
  20. if f[-3..-1] == ".rb"
  21. File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
  22. else
  23. File::makedirs(File.join($sitedir, *f.split(/\//)))
  24. end
  25. }
  26. module ActionMailer
  27. module AdvAttrAccessor #:nodoc:
  28. def self.append_features(base)
  29. super
  30. base.extend(ClassMethods)
  31. end
  32. module ClassMethods #:nodoc:
  33. def adv_attr_accessor(*names)
  34. names.each do |name|
  35. ivar = "@#{name}"
  36. define_method("#{name}=") do |value|
  37. instance_variable_set(ivar, value)
  38. end
  39. define_method(name) do |*parameters|
  40. raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1
  41. if parameters.empty?
  42. if instance_variables.include?(ivar)
  43. instance_variable_get(ivar)
  44. end
  45. else
  46. instance_variable_set(ivar, parameters.first)
  47. end
  48. end
  49. end
  50. end
  51. end
  52. end
  53. end
  54. require 'action_mailer/adv_attr_accessor'
  55. require 'action_mailer/part'
  56. require 'action_mailer/part_container'
  57. require 'action_mailer/utils'
  58. require 'tmail/net'
  59. module ActionMailer #:nodoc:
  60. # ActionMailer allows you to send email from your application using a mailer model and views.
  61. #
  62. # = Mailer Models
  63. # To use ActionMailer, you need to create a mailer model.
  64. #
  65. # $ script/generate mailer Notifier
  66. #
  67. # The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then
  68. # used to set variables to be used in the mail template, to change options on the mail, or
  69. # to add attachments.
  70. #
  71. # Examples:
  72. #
  73. # class Notifier < ActionMailer::Base
  74. # def signup_notification(recipient)
  75. # recipients recipient.email_address_with_name
  76. # from "system@example.com"
  77. # subject "New account information"
  78. # body "account" => recipient
  79. # end
  80. # end
  81. #
  82. # Mailer methods have the following configuration methods available.
  83. #
  84. # * <tt>recipients</tt> - Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the <tt>To:</tt> header.
  85. # * <tt>subject</tt> - The subject of your email. Sets the <tt>Subject:</tt> header.
  86. # * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header.
  87. # * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
  88. # * <tt>bcc</tt> - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc</tt> header.
  89. # * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
  90. # * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
  91. # * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
  92. #
  93. # The <tt>body</tt> method has special behavior. It takes a hash which generates an instance variable
  94. # named after each key in the hash containing the value that that key points to.
  95. #
  96. # So, for example, <tt>body "account" => recipient</tt> would result
  97. # in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
  98. # view.
  99. #
  100. # = Mailer Views
  101. # Like ActionController, each mailer class has a corresponding view directory
  102. # in which each method of the class looks for a template with its name.
  103. # To define a template to be used with a mailing, create an <tt>.rhtml</tt> file with the same name as the method
  104. # in your mailer model. For example, in the mailer defined above, the template at
  105. # <tt>app/views/notifier/signup_notification.rhtml</tt> would be used to generate the email.
  106. #
  107. # Variables defined in the model are accessible as instance variables in the view.
  108. #
  109. # Emails by default are sent in plain text, so a sample view for our model example might look like this:
  110. #
  111. # Hi <%= @account.name %>,
  112. # Thanks for joining our service! Please check back often.
  113. #
  114. # = Sending Mail
  115. # Once a mailer action and template are defined, you can deliver your message or create it and save it
  116. # for delivery later:
  117. #
  118. # Notifier.deliver_signup_notification(david) # sends the email
  119. # mail = Notifier.create_signup_notification(david) # => a tmail object
  120. # Notifier.deliver(mail)
  121. #
  122. # You never instantiate your mailer class. Rather, your delivery instance
  123. # methods are automatically wrapped in class methods that start with the word
  124. # <tt>deliver_</tt> followed by the name of the mailer method that you would
  125. # like to deliver. The <tt>signup_notification</tt> method defined above is
  126. # delivered by invoking <tt>Notifier.deliver_signup_notification</tt>.
  127. #
  128. # = HTML Email
  129. # To send mail as HTML, make sure your view (the <tt>.rhtml</tt> file) generates HTML and
  130. # set the content type to html.
  131. #
  132. # class MyMailer < ActionMailer::Base
  133. # def signup_notification(recipient)
  134. # recipients recipient.email_address_with_name
  135. # subject "New account information"
  136. # body "account" => recipient
  137. # from "system@example.com"
  138. # content_type "text/html" # Here's where the magic happens
  139. # end
  140. # end
  141. #
  142. # = Multipart Email
  143. # You can explicitly specify multipart messages:
  144. #
  145. # class ApplicationMailer < ActionMailer::Base
  146. # def signup_notification(recipient)
  147. # recipients recipient.email_address_with_name
  148. # subject "New account information"
  149. # from "system@example.com"
  150. #
  151. # part :content_type => "text/html",
  152. # :body => render_message("signup-as-html", :account => recipient)
  153. #
  154. # part "text/plain" do |p|
  155. # p.body = render_message("signup-as-plain", :account => recipient)
  156. # p.transfer_encoding = "base64"
  157. # end
  158. # end
  159. # end
  160. #
  161. # Multipart messages can also be used implicitly because ActionMailer will automatically
  162. # detect and use multipart templates, where each template is named after the name of the action, followed
  163. # by the content type. Each such detected template will be added as separate part to the message.
  164. #
  165. # For example, if the following templates existed:
  166. # * signup_notification.text.plain.rhtml
  167. # * signup_notification.text.html.rhtml
  168. # * signup_notification.text.xml.rxml
  169. # * signup_notification.text.x-yaml.rhtml
  170. #
  171. # Each would be rendered and added as a separate part to the message,
  172. # with the corresponding content type. The same body hash is passed to
  173. # each template.
  174. #
  175. # = Attachments
  176. # Attachments can be added by using the +attachment+ method.
  177. #
  178. # Example:
  179. #
  180. # class ApplicationMailer < ActionMailer::Base
  181. # # attachments
  182. # def signup_notification(recipient)
  183. # recipients recipient.email_address_with_name
  184. # subject "New account information"
  185. # from "system@example.com"
  186. #
  187. # attachment :content_type => "image/jpeg",
  188. # :body => File.read("an-image.jpg")
  189. #
  190. # attachment "application/pdf" do |a|
  191. # a.body = generate_your_pdf_here()
  192. # end
  193. # end
  194. # end
  195. #
  196. # = Configuration options
  197. #
  198. # These options are specified on the class level, like <tt>ActionMailer::Base.template_root = "/my/templates"</tt>
  199. #
  200. # * <tt>template_root</tt> - template root determines the base from which template references will be made.
  201. #
  202. # * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
  203. # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
  204. #
  205. # * <tt>server_settings</tt> - Allows detailed configuration of the server:
  206. # * <tt>:address</tt> Allows you to use a remote mail server. Just change it from its default "localhost" setting.
  207. # * <tt>:port</tt> On the off chance that your mail server doesn't run on port 25, you can change it.
  208. # * <tt>:domain</tt> If you need to specify a HELO domain, you can do it here.
  209. # * <tt>:user_name</tt> If your mail server requires authentication, set the username in this setting.
  210. # * <tt>:password</tt> If your mail server requires authentication, set the password in this setting.
  211. # * <tt>:authentication</tt> If your mail server requires authentication, you need to specify the authentication type here.
  212. # This is a symbol and one of :plain, :login, :cram_md5
  213. #
  214. # * <tt>raise_delivery_errors</tt> - whether or not errors should be raised if the email fails to be delivered.
  215. #
  216. # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test.
  217. # Sendmail is assumed to be present at "/usr/sbin/sendmail".
  218. #
  219. # * <tt>perform_deliveries</tt> - Determines whether deliver_* methods are actually carried out. By default they are,
  220. # but this can be turned off to help functional testing.
  221. #
  222. # * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful
  223. # for unit and functional testing.
  224. #
  225. # * <tt>default_charset</tt> - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also
  226. # pick a different charset from inside a method with <tt>@charset</tt>.
  227. # * <tt>default_content_type</tt> - The default content type used for the main part of the message. Defaults to "text/plain". You
  228. # can also pick a different content type from inside a method with <tt>@content_type</tt>.
  229. # * <tt>default_mime_version</tt> - The default mime version used for the message. Defaults to nil. You
  230. # can also pick a different value from inside a method with <tt>@mime_version</tt>. When multipart messages are in
  231. # use, <tt>@mime_version</tt> will be set to "1.0" if it is not set inside a method.
  232. # * <tt>default_implicit_parts_order</tt> - When a message is built implicitly (i.e. multiple parts are assembled from templates
  233. # which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to
  234. # ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client
  235. # and appear last in the mime encoded message. You can also pick a different order from inside a method with
  236. # <tt>@implicit_parts_order</tt>.
  237. class Base
  238. include AdvAttrAccessor, PartContainer
  239. # Action Mailer subclasses should be reloaded by the dispatcher in Rails
  240. # when Dependencies.mechanism = :load.
  241. include Reloadable::Subclasses
  242. private_class_method :new #:nodoc:
  243. class_inheritable_accessor :template_root
  244. cattr_accessor :logger
  245. @@server_settings = {
  246. :address => "localhost",
  247. :port => 25,
  248. :domain => 'localhost.localdomain',
  249. :user_name => nil,
  250. :password => nil,
  251. :authentication => nil
  252. }
  253. cattr_accessor :server_settings
  254. @@raise_delivery_errors = true
  255. cattr_accessor :raise_delivery_errors
  256. @@delivery_method = :smtp
  257. cattr_accessor :delivery_method
  258. @@perform_deliveries = true
  259. cattr_accessor :perform_deliveries
  260. @@deliveries = []
  261. cattr_accessor :deliveries
  262. @@default_charset = "utf-8"
  263. cattr_accessor :default_charset
  264. @@default_content_type = "text/plain"
  265. cattr_accessor :default_content_type
  266. @@default_mime_version = nil
  267. cattr_accessor :default_mime_version
  268. @@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ]
  269. cattr_accessor :default_implicit_parts_order
  270. # Specify the BCC addresses for the message
  271. adv_attr_accessor :bcc
  272. # Define the body of the message. This is either a Hash (in which case it
  273. # specifies the variables to pass to the template when it is rendered),
  274. # or a string, in which case it specifies the actual text of the message.
  275. adv_attr_accessor :body
  276. # Specify the CC addresses for the message.
  277. adv_attr_accessor :cc
  278. # Specify the charset to use for the message. This defaults to the
  279. # +default_charset+ specified for ActionMailer::Base.
  280. adv_attr_accessor :charset
  281. # Specify the content type for the message. This defaults to <tt>text/plain</tt>
  282. # in most cases, but can be automatically set in some situations.
  283. adv_attr_accessor :content_type
  284. # Specify the from address for the message.
  285. adv_attr_accessor :from
  286. # Specify additional headers to be added to the message.
  287. adv_attr_accessor :headers
  288. # Specify the order in which parts should be sorted, based on content-type.
  289. # This defaults to the value for the +default_implicit_parts_order+.
  290. adv_attr_accessor :implicit_parts_order
  291. # Override the mailer name, which defaults to an inflected version of the
  292. # mailer's class name. If you want to use a template in a non-standard
  293. # location, you can use this to specify that location.
  294. adv_attr_accessor :mailer_name
  295. # Defaults to "1.0", but may be explicitly given if needed.
  296. adv_attr_accessor :mime_version
  297. # The recipient addresses for the message, either as a string (for a single
  298. # address) or an array (for multiple addresses).
  299. adv_attr_accessor :recipients
  300. # The date on which the message was sent. If not set (the default), the
  301. # header will be set by the delivery agent.
  302. adv_attr_accessor :sent_on
  303. # Specify the subject of the message.
  304. adv_attr_accessor :subject
  305. # Specify the template name to use for current message. This is the "base"
  306. # template name, without the extension or directory, and may be used to
  307. # have multiple mailer methods share the same template.
  308. adv_attr_accessor :template
  309. # The mail object instance referenced by this mailer.
  310. attr_reader :mail
  311. class << self
  312. def method_missing(method_symbol, *parameters)#:nodoc:
  313. case method_symbol.id2name
  314. when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
  315. when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
  316. when "new" then nil
  317. else super
  318. end
  319. end
  320. # Receives a raw email, parses it into an email object, decodes it,
  321. # instantiates a new mailer, and passes the email object to the mailer
  322. # object's #receive method. If you want your mailer to be able to
  323. # process incoming messages, you'll need to implement a #receive
  324. # method that accepts the email object as a parameter:
  325. #
  326. # class MyMailer < ActionMailer::Base
  327. # def receive(mail)
  328. # ...
  329. # end
  330. # end
  331. def receive(raw_email)
  332. logger.info "Received mail:\n #{raw_email}" unless logger.nil?
  333. mail = TMail::Mail.parse(raw_email)
  334. mail.base64_decode
  335. new.receive(mail)
  336. end
  337. # Deliver the given mail object directly. This can be used to deliver
  338. # a preconstructed mail object, like:
  339. #
  340. # email = MyMailer.create_some_mail(parameters)
  341. # email.set_some_obscure_header "frobnicate"
  342. # MyMailer.deliver(email)
  343. def deliver(mail)
  344. new.deliver!(mail)
  345. end
  346. end
  347. # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
  348. # will be initialized according to the named method. If not, the mailer will
  349. # remain uninitialized (useful when you only need to invoke the "receive"
  350. # method, for instance).
  351. def initialize(method_name=nil, *parameters) #:nodoc:
  352. create!(method_name, *parameters) if method_name
  353. end
  354. # Initialize the mailer via the given +method_name+. The body will be
  355. # rendered and a new TMail::Mail object created.
  356. def create!(method_name, *parameters) #:nodoc:
  357. initialize_defaults(method_name)
  358. send(method_name, *parameters)
  359. # If an explicit, textual body has not been set, we check assumptions.
  360. unless String === @body
  361. # First, we look to see if there are any likely templates that match,
  362. # which include the content-type in their file name (i.e.,
  363. # "the_template_file.text.html.rhtml", etc.). Only do this if parts
  364. # have not already been specified manually.
  365. if @parts.empty?
  366. templates = Dir.glob("#{template_path}/#{@template}.*")
  367. templates.each do |path|
  368. # TODO: don't hardcode rhtml|rxml
  369. basename = File.basename(path)
  370. next unless md = /^([^\.]+)\.([^\.]+\.[^\+]+)\.(rhtml|rxml)$/.match(basename)
  371. template_name = basename
  372. content_type = md.captures[1].gsub('.', '/')
  373. @parts << Part.new(:content_type => content_type,
  374. :disposition => "inline", :charset => charset,
  375. :body => render_message(template_name, @body))
  376. end
  377. unless @parts.empty?
  378. @content_type = "multipart/alternative"
  379. @parts = sort_parts(@parts, @implicit_parts_order)
  380. end
  381. end
  382. # Then, if there were such templates, we check to see if we ought to
  383. # also render a "normal" template (without the content type). If a
  384. # normal template exists (or if there were no implicit parts) we render
  385. # it.
  386. template_exists = @parts.empty?
  387. template_exists ||= Dir.glob("#{template_path}/#{@template}.*").any? { |i| File.basename(i).split(".").length == 2 }
  388. @body = render_message(@template, @body) if template_exists
  389. # Finally, if there are other message parts and a textual body exists,
  390. # we shift it onto the front of the parts and set the body to nil (so
  391. # that create_mail doesn't try to render it in addition to the parts).
  392. if !@parts.empty? && String === @body
  393. @parts.unshift Part.new(:charset => charset, :body => @body)
  394. @body = nil
  395. end
  396. end
  397. # If this is a multipart e-mail add the mime_version if it is not
  398. # already set.
  399. @mime_version ||= "1.0" if !@parts.empty?
  400. # build the mail object itself
  401. @mail = create_mail
  402. end
  403. # Delivers a TMail::Mail object. By default, it delivers the cached mail
  404. # object (from the #create! method). If no cached mail object exists, and
  405. # no alternate has been given as the parameter, this will fail.
  406. def deliver!(mail = @mail)
  407. raise "no mail object available for delivery!" unless mail
  408. logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
  409. begin
  410. send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
  411. rescue Object => e
  412. raise e if raise_delivery_errors
  413. end
  414. return mail
  415. end
  416. private
  417. # Set up the default values for the various instance variables of this
  418. # mailer. Subclasses may override this method to provide different
  419. # defaults.
  420. def initialize_defaults(method_name)
  421. @charset ||= @@default_charset.dup
  422. @content_type ||= @@default_content_type.dup
  423. @implicit_parts_order ||= @@default_implicit_parts_order.dup
  424. @template ||= method_name
  425. @mailer_name ||= Inflector.underscore(self.class.name)
  426. @parts ||= []
  427. @headers ||= {}
  428. @body ||= {}
  429. @mime_version = @@default_mime_version.dup if @@default_mime_version
  430. end
  431. def render_message(method_name, body)
  432. render :file => method_name, :body => body
  433. end
  434. def render(opts)
  435. body = opts.delete(:body)
  436. initialize_template_class(body).render(opts)
  437. end
  438. def template_path
  439. "#{template_root}/#{mailer_name}"
  440. end
  441. def initialize_template_class(assigns)
  442. ActionView::Base.new(template_path, assigns, self)
  443. end
  444. def sort_parts(parts, order = [])
  445. order = order.collect { |s| s.downcase }
  446. parts = parts.sort do |a, b|
  447. a_ct = a.content_type.downcase
  448. b_ct = b.content_type.downcase
  449. a_in = order.include? a_ct
  450. b_in = order.include? b_ct
  451. s = case
  452. when a_in && b_in
  453. order.index(a_ct) <=> order.index(b_ct)
  454. when a_in
  455. -1
  456. when b_in
  457. 1
  458. else
  459. a_ct <=> b_ct
  460. end
  461. # reverse the ordering because parts that come last are displayed
  462. # first in mail clients
  463. (s * -1)
  464. end
  465. parts
  466. end
  467. def create_mail
  468. m = TMail::Mail.new
  469. m.subject, = quote_any_if_necessary(charset, subject)
  470. m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
  471. m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
  472. m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
  473. m.mime_version = mime_version unless mime_version.nil?
  474. m.date = sent_on.to_time rescue sent_on if sent_on
  475. headers.each { |k, v| m[k] = v }
  476. real_content_type, ctype_attrs = parse_content_type
  477. if @parts.empty?
  478. m.set_content_type(real_content_type, nil, ctype_attrs)
  479. m.body = Utils.normalize_new_lines(body)
  480. else
  481. if String === body
  482. part = TMail::Mail.new
  483. part.body = Utils.normalize_new_lines(body)
  484. part.set_content_type(real_content_type, nil, ctype_attrs)
  485. part.set_content_disposition "inline"
  486. m.parts << part
  487. end
  488. @parts.each do |p|
  489. part = (TMail::Mail === p ? p : p.to_mail(self))
  490. m.parts << part
  491. end
  492. if real_content_type =~ /multipart/
  493. ctype_attrs.delete "charset"
  494. m.set_content_type(real_content_type, nil, ctype_attrs)
  495. end
  496. end
  497. @mail = m
  498. end
  499. def perform_delivery_smtp(mail)
  500. destinations = mail.destinations
  501. mail.ready_to_send
  502. Net::SMTP.start(server_settings[:address], server_settings[:port], server_settings[:domain],
  503. server_settings[:user_name], server_settings[:password], server_settings[:authentication]) do |smtp|
  504. smtp.sendmail(mail.encoded, mail.from, destinations)
  505. end
  506. end
  507. def perform_delivery_sendmail(mail)
  508. IO.popen("/usr/sbin/sendmail -i -t","w+") do |sm|
  509. sm.print(mail.encoded.gsub(/\r/, ''))
  510. sm.flush
  511. end
  512. end
  513. def perform_delivery_test(mail)
  514. deliveries << mail
  515. end
  516. end
  517. end
  518. module ActionMailer
  519. module Helpers #:nodoc:
  520. def self.append_features(base) #:nodoc:
  521. super
  522. # Initialize the base module to aggregate its helpers.
  523. base.class_inheritable_accessor :master_helper_module
  524. base.master_helper_module = Module.new
  525. # Extend base with class methods to declare helpers.
  526. base.extend(ClassMethods)
  527. base.class_eval do
  528. # Wrap inherited to create a new master helper module for subclasses.
  529. class << self
  530. alias_method :inherited_without_helper, :inherited
  531. alias_method :inherited, :inherited_with_helper
  532. end
  533. # Wrap initialize_template_class to extend new template class
  534. # instances with the master helper module.
  535. alias_method :initialize_template_class_without_helper, :initialize_template_class
  536. alias_method :initialize_template_class, :initialize_template_class_with_helper
  537. end
  538. end
  539. module ClassMethods
  540. # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
  541. # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
  542. # available to the templates.
  543. def add_template_helper(helper_module) #:nodoc:
  544. master_helper_module.module_eval "include #{helper_module}"
  545. end
  546. # Declare a helper:
  547. # helper :foo
  548. # requires 'foo_helper' and includes FooHelper in the template class.
  549. # helper FooHelper
  550. # includes FooHelper in the template class.
  551. # helper { def foo() "#{bar} is the very best" end }
  552. # evaluates the block in the template class, adding method #foo.
  553. # helper(:three, BlindHelper) { def mice() 'mice' end }
  554. # does all three.
  555. def helper(*args, &block)
  556. args.flatten.each do |arg|
  557. case arg
  558. when Module
  559. add_template_helper(arg)
  560. when String, Symbol
  561. file_name = arg.to_s.underscore + '_helper'
  562. class_name = file_name.camelize
  563. begin
  564. require_dependency(file_name)
  565. rescue LoadError => load_error
  566. requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
  567. msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
  568. raise LoadError.new(msg).copy_blame!(load_error)
  569. end
  570. add_template_helper(class_name.constantize)
  571. else
  572. raise ArgumentError, 'helper expects String, Symbol, or Module argument'
  573. end
  574. end
  575. # Evaluate block in template class if given.
  576. master_helper_module.module_eval(&block) if block_given?
  577. end
  578. # Declare a controller method as a helper. For example,
  579. # helper_method :link_to
  580. # def link_to(name, options) ... end
  581. # makes the link_to controller method available in the view.
  582. def helper_method(*methods)
  583. methods.flatten.each do |method|
  584. master_helper_module.module_eval <<-end_eval
  585. def #{method}(*args, &block)
  586. controller.send(%(#{method}), *args, &block)
  587. end
  588. end_eval
  589. end
  590. end
  591. # Declare a controller attribute as a helper. For example,
  592. # helper_attr :name
  593. # attr_accessor :name
  594. # makes the name and name= controller methods available in the view.
  595. # The is a convenience wrapper for helper_method.
  596. def helper_attr(*attrs)
  597. attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
  598. end
  599. private
  600. def inherited_with_helper(child)
  601. inherited_without_helper(child)
  602. begin
  603. child.master_helper_module = Module.new
  604. child.master_helper_module.send :include, master_helper_module
  605. child.helper child.name.underscore
  606. rescue MissingSourceFile => e
  607. raise unless e.is_missing?("helpers/#{child.name.underscore}_helper")
  608. end
  609. end
  610. end
  611. private
  612. # Extend the template class instance with our controller's helper module.
  613. def initialize_template_class_with_helper(assigns)
  614. returning(template = initialize_template_class_without_helper(assigns)) do
  615. template.extend self.class.master_helper_module
  616. end
  617. end
  618. end
  619. endrequire 'text/format'
  620. module MailHelper
  621. # Uses Text::Format to take the text and format it, indented two spaces for
  622. # each line, and wrapped at 72 columns.
  623. def block_format(text)
  624. formatted = text.split(/\n\r\n/).collect { |paragraph|
  625. Text::Format.new(
  626. :columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
  627. ).format
  628. }.join("\n")
  629. # Make list points stand on their own line
  630. formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
  631. formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
  632. formatted
  633. end
  634. end
  635. require 'action_mailer/adv_attr_accessor'
  636. require 'action_mailer/part_container'
  637. require 'action_mailer/utils'
  638. module ActionMailer
  639. # Represents a subpart of an email message. It shares many similar
  640. # attributes of ActionMailer::Base. Although you can create parts manually
  641. # and add them to the #parts list of the mailer, it is easier
  642. # to use the helper methods in ActionMailer::PartContainer.
  643. class Part
  644. include ActionMailer::AdvAttrAccessor
  645. include ActionMailer::PartContainer
  646. # Represents the body of the part, as a string. This should not be a
  647. # Hash (like ActionMailer::Base), but if you want a template to be rendered
  648. # into the body of a subpart you can do it with the mailer's #render method
  649. # and assign the result here.
  650. adv_attr_accessor :body
  651. # Specify the charset for this subpart. By default, it will be the charset
  652. # of the containing part or mailer.
  653. adv_attr_accessor :charset
  654. # The content disposition of this part, typically either "inline" or
  655. # "attachment".
  656. adv_attr_accessor :content_disposition
  657. # The content type of the part.
  658. adv_attr_accessor :content_type
  659. # The filename to use for this subpart (usually for attachments).
  660. adv_attr_accessor :filename
  661. # Accessor for specifying additional headers to include with this part.
  662. adv_attr_accessor :headers
  663. # The transfer encoding to use for this subpart, like "base64" or
  664. # "quoted-printable".
  665. adv_attr_accessor :transfer_encoding
  666. # Create a new part from the given +params+ hash. The valid params keys
  667. # correspond to the accessors.
  668. def initialize(params)
  669. @content_type = params[:content_type]
  670. @content_disposition = params[:disposition] || "inline"
  671. @charset = params[:charset]
  672. @body = params[:body]
  673. @filename = params[:filename]
  674. @transfer_encoding = params[:transfer_encoding] || "quoted-printable"
  675. @headers = params[:headers] || {}
  676. @parts = []
  677. end
  678. # Convert the part to a mail object which can be included in the parts
  679. # list of another mail object.
  680. def to_mail(defaults)
  681. part = TMail::Mail.new
  682. real_content_type, ctype_attrs = parse_content_type(defaults)
  683. if @parts.empty?
  684. part.content_transfer_encoding = transfer_encoding || "quoted-printable"
  685. case (transfer_encoding || "").downcase
  686. when "base64" then
  687. part.body = TMail::Base64.folding_encode(body)
  688. when "quoted-printable"
  689. part.body = [Utils.normalize_new_lines(body)].pack("M*")
  690. else
  691. part.body = body
  692. end
  693. # Always set the content_type after setting the body and or parts!
  694. # Also don't set filename and name when there is none (like in
  695. # non-attachment parts)
  696. if content_disposition == "attachment"
  697. ctype_attrs.delete "charset"
  698. part.set_content_type(real_content_type, nil,
  699. squish("name" => filename).merge(ctype_attrs))
  700. part.set_content_disposition(content_disposition,
  701. squish("filename" => filename).merge(ctype_attrs))
  702. else
  703. part.set_content_type(real_content_type, nil, ctype_attrs)
  704. part.set_content_disposition(content_disposition)
  705. end
  706. else
  707. if String === body
  708. part = TMail::Mail.new
  709. part.body = body
  710. part.set_content_type(real_content_type, nil, ctype_attrs)
  711. part.set_content_disposition "inline"
  712. m.parts << part
  713. end
  714. @parts.each do |p|
  715. prt = (TMail::Mail === p ? p : p.to_mail(defaults))
  716. part.parts << prt
  717. end
  718. part.set_content_type(real_content_type, nil, ctype_attrs) if real_content_type =~ /multipart/
  719. end
  720. headers.each { |k,v| part[k] = v }
  721. part
  722. end
  723. private
  724. def squish(values={})
  725. values.delete_if { |k,v| v.nil? }
  726. end
  727. end
  728. end
  729. module ActionMailer
  730. # Accessors and helpers that ActionMailer::Base and ActionMailer::Part have
  731. # in common. Using these helpers you can easily add subparts or attachments
  732. # to your message:
  733. #
  734. # def my_mail_message(...)
  735. # ...
  736. # part "text/plain" do |p|
  737. # p.body "hello, world"
  738. # p.transfer_encoding "base64"
  739. # end
  740. #
  741. # attachment "image/jpg" do |a|
  742. # a.body = File.read("hello.jpg")
  743. # a.filename = "hello.jpg"
  744. # end
  745. # end
  746. module PartContainer
  747. # The list of subparts of this container
  748. attr_reader :parts
  749. # Add a part to a multipart message, with the given content-type. The
  750. # part itself is yielded to the block so that other properties (charset,
  751. # body, headers, etc.) can be set on it.
  752. def part(params)
  753. params = {:content_type => params} if String === params
  754. part = Part.new(params)
  755. yield part if block_given?
  756. @parts << part
  757. end
  758. # Add an attachment to a multipart message. This is simply a part with the
  759. # content-disposition set to "attachment".
  760. def attachment(params, &block)
  761. params = { :content_type => params } if String === params
  762. params = { :disposition => "attachment",
  763. :transfer_encoding => "base64" }.merge(params)
  764. part(params, &block)
  765. end
  766. private
  767. def parse_content_type(defaults=nil)
  768. return [defaults && defaults.content_type, {}] if content_type.blank?
  769. ctype, *attrs = content_type.split(/;\s*/)
  770. attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
  771. [ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)]
  772. end
  773. end
  774. end
  775. module ActionMailer
  776. module Quoting #:nodoc:
  777. # Convert the given text into quoted printable format, with an instruction
  778. # that the text be eventually interpreted in the given charset.
  779. def quoted_printable(text, charset)
  780. text = text.gsub( /[^a-z ]/i ) { quoted_printable_encode($&) }.
  781. gsub( / /, "_" )
  782. "=?#{charset}?Q?#{text}?="
  783. end
  784. # Convert the given character to quoted printable format, taking into
  785. # account multi-byte characters (if executing with $KCODE="u", for instance)
  786. def quoted_printable_encode(character)
  787. result = ""
  788. character.each_byte { |b| result << "=%02x" % b }
  789. result
  790. end
  791. # A quick-and-dirty regexp for determining whether a string contains any
  792. # characters that need escaping.
  793. if !defined?(CHARS_NEEDING_QUOTING)
  794. CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/
  795. end
  796. # Quote the given text if it contains any "illegal" characters
  797. def quote_if_necessary(text, charset)
  798. (text =~ CHARS_NEEDING_QUOTING) ?
  799. quoted_printable(text, charset) :
  800. text
  801. end
  802. # Quote any of the given strings if they contain any "illegal" characters
  803. def quote_any_if_necessary(charset, *args)
  804. args.map { |v| quote_if_necessary(v, charset) }
  805. end
  806. # Quote the given address if it needs to be. The address may be a
  807. # regular email address, or it can be a phrase followed by an address in
  808. # brackets. The phrase is the only part that will be quoted, and only if
  809. # it needs to be. This allows extended characters to be used in the
  810. # "to", "from", "cc", and "bcc" headers.
  811. def quote_address_if_necessary(address, charset)
  812. if Array === address
  813. address.map { |a| quote_address_if_necessary(a, charset) }
  814. elsif address =~ /^(\S.*)\s+(<.*>)$/
  815. address = $2
  816. phrase = quote_if_necessary($1.gsub(/^['"](.*)['"]$/, '\1'), charset)
  817. "\"#{phrase}\" #{address}"
  818. else
  819. address
  820. end
  821. end
  822. # Quote any of the given addresses, if they need to be.
  823. def quote_any_address_if_necessary(charset, *args)
  824. args.map { |v| quote_address_if_necessary(v, charset) }
  825. end
  826. end
  827. end
  828. module ActionMailer
  829. module Utils #:nodoc:
  830. def normalize_new_lines(text)
  831. text.to_s.gsub(/\r\n?/, "\n")
  832. end
  833. module_function :normalize_new_lines
  834. end
  835. end
  836. #--
  837. # Text::Format for Ruby
  838. # Version 0.63
  839. #
  840. # Copyright (c) 2002 - 2003 Austin Ziegler
  841. #
  842. # $Id: format.rb,v 1.1.1.1 2004/10/14 11:59:57 webster132 Exp $
  843. #
  844. # ==========================================================================
  845. # Revision History ::
  846. # YYYY.MM.DD Change ID Developer
  847. # Description
  848. # --------------------------------------------------------------------------
  849. # 2002.10.18 Austin Ziegler
  850. # Fixed a minor problem with tabs not being counted. Changed
  851. # abbreviations from Hash to Array to better suit Ruby's
  852. # capabilities. Fixed problems with the way that Array arguments
  853. # are handled in calls to the major object types, excepting in
  854. # Text::Format#expand and Text::Format#unexpand (these will
  855. # probably need to be fixed).
  856. # 2002.10.30 Austin Ziegler
  857. # Fixed the ordering of the <=> for binary tests. Fixed
  858. # Text::Format#expand and Text::Format#unexpand to handle array
  859. # arguments better.
  860. # 2003.01.24 Austin Ziegler
  861. # Fixed a problem with Text::Format::RIGHT_FILL handling where a
  862. # single word is larger than #columns. Removed Comparable
  863. # capabilities (<=> doesn't make sense; == does). Added Symbol
  864. # equivalents for the Hash initialization. Hash initialization has
  865. # been modified so that values are set as follows (Symbols are
  866. # highest priority; strings are middle; defaults are lowest):
  867. # @columns = arg[:columns] || arg['columns'] || @columns
  868. # Added #hard_margins, #split_rules, #hyphenator, and #split_words.
  869. # 2003.02.07 Austin Ziegler
  870. # Fixed the installer for proper case-sensitive handling.
  871. # 2003.03.28 Austin Ziegler
  872. # Added the ability for a hyphenator to receive the formatter
  873. # object. Fixed a bug for strings matching /\A\s*\Z/ failing
  874. # entirely. Fixed a test case failing under 1.6.8.
  875. # 2003.04.04 Austin Ziegler
  876. # Handle the case of hyphenators returning nil for first/rest.
  877. # 2003.09.17 Austin Ziegler
  878. # Fixed a problem where #paragraphs(" ") was raising
  879. # NoMethodError.
  880. #
  881. # ==========================================================================
  882. #++
  883. module Text #:nodoc:
  884. # Text::Format for Ruby is copyright 2002 - 2005 by Austin Ziegler. It
  885. # is available under Ruby's licence, the Perl Artistic licence, or the
  886. # GNU GPL version 2 (or at your option, any later version). As a
  887. # special exception, for use with official Rails (provided by the
  888. # rubyonrails.org development team) and any project created with
  889. # official Rails, the following alternative MIT-style licence may be
  890. # used:
  891. #
  892. # == Text::Format Licence for Rails and Rails Applications
  893. # Permission is hereby granted, free of charge, to any person
  894. # obtaining a copy of this software and associated documentation files
  895. # (the "Software"), to deal in the Software without restriction,
  896. # including without limitation the rights to use, copy, modify, merge,
  897. # publish, distribute, sublicense, and/or sell copies of the Software,
  898. # and to permit persons to whom the Software is furnished to do so,
  899. # subject to the following conditions:
  900. #
  901. # * The names of its contributors may not be used to endorse or
  902. # promote products derived from this software without specific prior
  903. # written permission.
  904. #
  905. # The above copyright notice and this permission notice shall be
  906. # included in all copies or substantial portions of the Software.
  907. #
  908. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  909. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  910. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  911. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  912. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  913. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  914. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  915. # SOFTWARE.
  916. class Format
  917. VERSION = '0.63'
  918. # Local abbreviations. More can be added with Text::Format.abbreviations
  919. ABBREV = [ 'Mr', 'Mrs', 'Ms', 'Jr', 'Sr' ]
  920. # Formatting values
  921. LEFT_ALIGN = 0
  922. RIGHT_ALIGN = 1
  923. RIGHT_FILL = 2
  924. JUSTIFY = 3
  925. # Word split modes (only applies when #hard_margins is true).
  926. SPLIT_FIXED = 1
  927. SPLIT_CONTINUATION = 2
  928. SPLIT_HYPHENATION = 4
  929. SPLIT_CONTINUATION_FIXED = SPLIT_CONTINUATION | SPLIT_FIXED
  930. SPLIT_HYPHENATION_FIXED = SPLIT_HYPHENATION | SPLIT_FIXED
  931. SPLIT_HYPHENATION_CONTINUATION = SPLIT_HYPHENATION | SPLIT_CONTINUATION
  932. SPLIT_ALL = SPLIT_HYPHENATION | SPLIT_CONTINUATION | SPLIT_FIXED
  933. # Words forcibly split by Text::Format will be stored as split words.
  934. # This class represents a word forcibly split.
  935. class SplitWord
  936. # The word that was split.
  937. attr_reader :word
  938. # The first part of the word that was split.
  939. attr_reader :first
  940. # The remainder of the word that was split.
  941. attr_reader :rest
  942. def initialize(word, first, rest) #:nodoc:
  943. @word = word
  944. @first = first
  945. @rest = rest
  946. end
  947. end
  948. private
  949. LEQ_RE = /[.?!]['"]?$/
  950. def brk_re(i) #:nodoc:
  951. %r/((?:\S+\s+){#{i}})(.+)/
  952. end
  953. def posint(p) #:nodoc:
  954. p.to_i.abs
  955. end
  956. public
  957. # Compares two Text::Format objects. All settings of the objects are
  958. # compared *except* #hyphenator. Generated results (e.g., #split_words)
  959. # are not compared, either.
  960. def ==(o)
  961. (@text == o.text) &&
  962. (@columns == o.columns) &&
  963. (@left_margin == o.left_margin) &&
  964. (@right_margin == o.right_margin) &&
  965. (@hard_margins == o.hard_margins) &&
  966. (@split_rules == o.split_rules) &&
  967. (@first_indent == o.first_indent) &&
  968. (@body_indent == o.body_indent) &&
  969. (@tag_text == o.tag_text) &&
  970. (@tabstop == o.tabstop) &&
  971. (@format_style == o.format_style) &&
  972. (@extra_space == o.extra_space) &&
  973. (@tag_paragraph == o.tag_paragraph) &&
  974. (@nobreak == o.nobreak) &&
  975. (@abbreviations == o.abbreviations) &&
  976. (@nobreak_regex == o.nobreak_regex)
  977. end
  978. # The text to be manipulated. Note that value is optional, but if the
  979. # formatting functions are called without values, this text is what will
  980. # be formatted.
  981. #
  982. # *Default*:: <tt>[]</tt>
  983. # <b>Used in</b>:: All methods
  984. attr_accessor :text
  985. # The total width of the format area. The margins, indentation, and text
  986. # are formatted into this space.
  987. #
  988. # COLUMNS
  989. # <-------------------------------------------------------------->
  990. # <-----------><------><---------------------------><------------>
  991. # left margin indent text is formatted into here right margin
  992. #
  993. # *Default*:: <tt>72</tt>
  994. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  995. # <tt>#center</tt>
  996. attr_reader :columns
  997. # The total width of the format area. The margins, indentation, and text
  998. # are formatted into this space. The value provided is silently
  999. # converted to a positive integer.
  1000. #
  1001. # COLUMNS
  1002. # <-------------------------------------------------------------->
  1003. # <-----------><------><---------------------------><------------>
  1004. # left margin indent text is formatted into here right margin
  1005. #
  1006. # *Default*:: <tt>72</tt>
  1007. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  1008. # <tt>#center</tt>
  1009. def columns=(c)
  1010. @columns = posint(c)
  1011. end
  1012. # The number of spaces used for the left margin.
  1013. #
  1014. # columns
  1015. # <-------------------------------------------------------------->
  1016. # <-----------><------><---------------------------><------------>
  1017. # LEFT MARGIN indent text is formatted into here right margin
  1018. #
  1019. # *Default*:: <tt>0</tt>
  1020. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  1021. # <tt>#center</tt>
  1022. attr_reader :left_margin
  1023. # The number of spaces used for the left margin. The value provided is
  1024. # silently converted to a positive integer value.
  1025. #
  1026. # columns
  1027. # <-------------------------------------------------------------->
  1028. # <-----------><------><---------------------------><------------>
  1029. # LEFT MARGIN indent text is formatted into here right margin
  1030. #
  1031. # *Default*:: <tt>0</tt>
  1032. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  1033. # <tt>#center</tt>
  1034. def left_margin=(left)
  1035. @left_margin = posint(left)
  1036. end
  1037. # The number of spaces used for the right margin.
  1038. #
  1039. # columns
  1040. # <-------------------------------------------------------------->
  1041. # <-----------><------><---------------------------><------------>
  1042. # left margin indent text is formatted into here RIGHT MARGIN
  1043. #
  1044. # *Default*:: <tt>0</tt>
  1045. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  1046. # <tt>#center</tt>
  1047. attr_reader :right_margin
  1048. # The number of spaces used for the right margin. The value provided is
  1049. # silently converted to a positive integer value.
  1050. #
  1051. # columns
  1052. # <-------------------------------------------------------------->
  1053. # <-----------><------><---------------------------><------------>
  1054. # left margin indent text is formatted into here RIGHT MARGIN
  1055. #
  1056. # *Default*:: <tt>0</tt>
  1057. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>,
  1058. # <tt>#center</tt>
  1059. def right_margin=(r)
  1060. @right_margin = posint(r)
  1061. end
  1062. # The number of spaces to indent the first line of a paragraph.
  1063. #
  1064. # columns
  1065. # <-------------------------------------------------------------->
  1066. # <-----------><------><---------------------------><------------>
  1067. # left margin INDENT text is formatted into here right margin
  1068. #
  1069. # *Default*:: <tt>4</tt>
  1070. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>
  1071. attr_reader :first_indent
  1072. # The number of spaces to indent the first line of a paragraph. The
  1073. # value provided is silently converted to a positive integer value.
  1074. #
  1075. # columns
  1076. # <-------------------------------------------------------------->
  1077. # <-----------><------><---------------------------><------------>
  1078. # left margin INDENT text is formatted into here right margin
  1079. #
  1080. # *Default*:: <tt>4</tt>
  1081. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>
  1082. def first_indent=(f)
  1083. @first_indent = posint(f)
  1084. end
  1085. # The number of spaces to indent all lines after the first line of a
  1086. # paragraph.
  1087. #
  1088. # columns
  1089. # <-------------------------------------------------------------->
  1090. # <-----------><------><---------------------------><------------>
  1091. # left margin INDENT text is formatted into here right margin
  1092. #
  1093. # *Default*:: <tt>0</tt>
  1094. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>
  1095. attr_reader :body_indent
  1096. # The number of spaces to indent all lines after the first line of
  1097. # a paragraph. The value provided is silently converted to a
  1098. # positive integer value.
  1099. #
  1100. # columns
  1101. # <-------------------------------------------------------------->
  1102. # <-----------><------><---------------------------><------------>
  1103. # left margin INDENT text is formatted into here right margin
  1104. #
  1105. # *Default*:: <tt>0</tt>
  1106. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>
  1107. def body_indent=(b)
  1108. @body_indent = posint(b)
  1109. end
  1110. # Normally, words larger than the format area will be placed on a line
  1111. # by themselves. Setting this to +true+ will force words larger than the
  1112. # format area to be split into one or more "words" each at most the size
  1113. # of the format area. The first line and the original word will be
  1114. # placed into <tt>#split_words</tt>. Note that this will cause the
  1115. # output to look *similar* to a #format_style of JUSTIFY. (Lines will be
  1116. # filled as much as possible.)
  1117. #
  1118. # *Default*:: +false+
  1119. # <b>Used in</b>:: <tt>#format</tt>, <tt>#paragraphs</tt>
  1120. attr_accessor :hard_margins
  1121. # An array of words split during formatting if #hard_margins is set to
  1122. # +true+.
  1123. # #split_words << Text::Format::SplitWord.new(word, first, rest)
  1124. attr_reader :split_words
  1125. # The object responsible for hyphenating. It must respond to
  1126. # #hyphena

Large files files are truncated, but you can click here to view the full file