rmsgen 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE +674 -0
  4. data/README.md +55 -0
  5. data/Rakefile +13 -0
  6. data/bin/checkurl +2 -0
  7. data/bin/publish +3 -0
  8. data/bin/rmsgen +10 -0
  9. data/features/append_tabbed_line.feature +23 -0
  10. data/features/config/output_file.feature +59 -0
  11. data/features/config/reading_config.feature +24 -0
  12. data/features/link_to_polnote.feature +38 -0
  13. data/features/multiple_notes.feature +54 -0
  14. data/features/multiple_url.feature +31 -0
  15. data/features/raw_email.feature +101 -0
  16. data/features/setting_title.feature +22 -0
  17. data/features/standard_pol_note.feature +41 -0
  18. data/features/step_definitions/bin_steps.rb +3 -0
  19. data/features/step_definitions/file_steps.rb +3 -0
  20. data/features/step_definitions/polnote_steps.rb +25 -0
  21. data/features/step_definitions/title_steps.rb +10 -0
  22. data/features/step_definitions/urgent_polnote_steps.rb +24 -0
  23. data/features/support/env.rb +7 -0
  24. data/features/support/hooks.rb +8 -0
  25. data/features/urgent_polnote.feature +33 -0
  26. data/lib/rmsgen/cli/main.rb +21 -0
  27. data/lib/rmsgen/compresser.rb +33 -0
  28. data/lib/rmsgen/fs_polnote_group.rb +12 -0
  29. data/lib/rmsgen/imap_polnote_group.rb +66 -0
  30. data/lib/rmsgen/inquirer.rb +90 -0
  31. data/lib/rmsgen/link.rb +12 -0
  32. data/lib/rmsgen/part_group.rb +23 -0
  33. data/lib/rmsgen/polnote.rb +41 -0
  34. data/lib/rmsgen/runtime.rb +56 -0
  35. data/lib/rmsgen/script.rb +38 -0
  36. data/lib/rmsgen/titleizer.rb +43 -0
  37. data/lib/rmsgen/version.rb +3 -0
  38. data/lib/rmsgen.rb +21 -0
  39. data/lib/templates/polnote.erb +2 -0
  40. data/lib/templates/title.erb +1 -0
  41. data/rmsgen.gemspec +21 -0
  42. data/spec/fake_gets.rb +25 -0
  43. data/spec/fixtures/imap_note +3 -0
  44. data/spec/fixtures/link_to_polnote +7 -0
  45. data/spec/fixtures/multiline_note +9 -0
  46. data/spec/fixtures/urgent_note +39 -0
  47. data/spec/fs_polnote_group_spec.rb +37 -0
  48. data/spec/imap_polnote_group_spec.rb +43 -0
  49. data/spec/inqirer_spec.rb +55 -0
  50. data/spec/part_group_spec.rb +21 -0
  51. data/spec/polnote_spec.rb +60 -0
  52. data/spec/runtime_spec.rb +52 -0
  53. data/spec/support/fake_gets.rb +27 -0
  54. metadata +103 -0
@@ -0,0 +1,12 @@
1
+ module Rmsgen
2
+ class FsPolnoteGroup
3
+ def initialize(dir=nil)
4
+ splat_dir = "#{dir}/*"
5
+ @raw_notes = Dir[splat_dir].map { |f| File.read(f) }
6
+ @notes = @raw_notes.map { |note| Rmsgen::Polnote.new(note) }
7
+ end
8
+ def all
9
+ @notes
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,66 @@
1
+ module Rmsgen
2
+ class IMAPPolnoteGroup
3
+ require 'net/imap'
4
+
5
+ def initialize(imap, options={})
6
+ @imap = imap
7
+ @login = options['imap_login']
8
+ @password = options['imap_password']
9
+ end
10
+
11
+ def fetch_notes
12
+ authenticate
13
+ follow_inbox
14
+ find_all_from_rms
15
+ end
16
+
17
+ def note_ids
18
+ authenticate
19
+ follow_inbox
20
+ @imap.search(["FROM", 'rms@gnu.org'])
21
+ end
22
+
23
+ def find(id)
24
+ follow_inbox
25
+ fetch_message_body(id)
26
+ end
27
+
28
+ def archive_polnote(id)
29
+ authenticate
30
+ follow_inbox
31
+ archived = false
32
+ @imap.search(["FROM", 'rms@gnu.org']).each do |note_id|
33
+ if note_id.to_i == id.to_i
34
+ @imap.copy id.to_i, 'INBOX.old-messages'
35
+ @imap.store(id.to_i, "+FLAGS", [:Deleted])
36
+ @imap.expunge
37
+ archived = true
38
+ end
39
+ end
40
+ archived
41
+ end
42
+
43
+ private
44
+
45
+ def authenticate
46
+ @imap.authenticate 'LOGIN', @login, @password
47
+ end
48
+
49
+ def follow_inbox
50
+ @imap.select 'INBOX'
51
+ end
52
+
53
+ def find_all_from_rms
54
+ if note_ids && note_ids.any?
55
+ note_ids.map { |id| fetch_message_body(id) }
56
+ end
57
+ end
58
+
59
+ def fetch_message_body(id)
60
+ fetch_result = @imap.fetch id, 'BODY[TEXT]'
61
+ if fetch_result && fetch_result.any?
62
+ fetch_result[0].attr['BODY[TEXT]']
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,90 @@
1
+ module Rmsgen
2
+ class Inquirer
3
+ PARTS = { :url => /^http/,
4
+ :note =>/\[Link/,
5
+ :duration => /^For.*week.*$/,
6
+ :indendation => /^ /
7
+ }
8
+
9
+ attr_reader :polnote
10
+
11
+ def initialize polnote, stdout=$stdout, answers=nil
12
+ @parts_seen = []
13
+ @polnote = polnote
14
+ @parts = @polnote.parts
15
+ @stdout = stdout
16
+ @script = Script.new(stdout)
17
+ @answers = answers ||= []
18
+ run!
19
+ end
20
+
21
+ def body
22
+ @parts_seen.join PartGroup::DELIMETER
23
+ end
24
+
25
+ def self.inquire_about_note(note, stdout=$stdout)
26
+ stdout.puts note.body
27
+ stdout.puts
28
+ note.titleize
29
+ note.inquire
30
+ stdout.puts
31
+ note
32
+ end
33
+
34
+ private
35
+
36
+ def run!
37
+ @parts.each do |part|
38
+ if part =~ PARTS[:duration]
39
+ inquire_about_expiration
40
+ elsif part =~ PARTS[:url]
41
+ inquire_about_link part
42
+ elsif part =~ PARTS[:note]
43
+ inquire_about_polnote_link part
44
+ elsif part =~ PARTS[:indendation]
45
+ append_to_previous_paragraph part
46
+ else
47
+ @parts_seen << part
48
+ end
49
+ end
50
+ end
51
+
52
+ def inquire_about_link url
53
+ if @answers.empty?
54
+ @script.announce current_part
55
+ text = @script.prompt_for_text
56
+ else
57
+ text = @answers.shift
58
+ end
59
+ if text && !text.empty?
60
+ link = Link.new text, url
61
+ current_part.gsub! text, link.to_s
62
+ end
63
+ end
64
+
65
+ def inquire_about_expiration
66
+ @polnote.expires_on = @script.prompt_for_expiry_date
67
+ end
68
+
69
+ def append_to_previous_paragraph part
70
+ current_part << " #{part.strip}#{PartGroup::DELIMETER}"
71
+ end
72
+
73
+ def current_part
74
+ @parts_seen.last
75
+ end
76
+
77
+ def inquire_about_polnote_link part
78
+ if @answers.any?
79
+ href = @answers.shift
80
+ text = @answers.shift
81
+ else
82
+ href = @script.prompt_for_polnote_link part
83
+ @script.announce current_part
84
+ text = @script.prompt_for_text
85
+ end
86
+ link = Link.new text, href
87
+ current_part.gsub! text, link.to_s
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,12 @@
1
+ module Rmsgen
2
+ class Link
3
+ def initialize(text, href)
4
+ @text = text
5
+ @href = href
6
+ end
7
+
8
+ def to_s
9
+ %{<a href='#{@href}'>#{@text}</a>}
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ class PartGroup < Array
2
+ attr_reader :text
3
+
4
+ DELIMETER = "\n\n"
5
+
6
+ def initialize(text)
7
+ @text = text
8
+ assign_parts!
9
+ end
10
+
11
+ def assign_parts!
12
+ if @text.match /\r\n\r\n/
13
+ @text.gsub!(/\r\n\r\n/, "\n\n")
14
+ @text.gsub!(/\r\n/, " ")
15
+ @text.gsub!(/\n\n\n\n/, "")
16
+ else
17
+ @text.gsub!(/\n\n/, '[newline]')
18
+ @text.gsub!(/\n/, ' ')
19
+ @text.gsub!('[newline]', "\n\n")
20
+ end
21
+ @text.split(DELIMETER).delete_if(&:empty?).each { |p| self << p }
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ module Rmsgen
2
+ class Polnote
3
+ attr_accessor :id, :title, :body, :expires_on
4
+
5
+ URGENT_SUBJECT = 'Subject: Urgent note'
6
+ TEMPLATE = File.join(File.dirname(__FILE__), '..', 'templates', 'polnote.erb')
7
+
8
+ def initialize(source, options={})
9
+ @body = source.dup
10
+ @urgent = source.include? URGENT_SUBJECT
11
+ @id = options[:id]
12
+ compress!
13
+ end
14
+
15
+ def urgent?
16
+ @urgent
17
+ end
18
+
19
+ def titleize
20
+ @title = Titleizer.new(self).body
21
+ end
22
+
23
+ def inquire
24
+ @body = Inquirer.new(self).body
25
+ end
26
+
27
+ def parts
28
+ PartGroup.new(@body)
29
+ end
30
+
31
+ def to_html
32
+ ERB.new(File.read(TEMPLATE)).result(binding)
33
+ end
34
+
35
+ private
36
+
37
+ def compress!
38
+ @body = Compresser.new(self).body
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
1
+ module Rmsgen
2
+ class Runtime
3
+ def initialize(config)
4
+ @config = config
5
+ raise "Ensure you have populated a config file" unless @config
6
+ @output = @config['output_file']
7
+ @notes = fetch_notes
8
+ run!
9
+ end
10
+
11
+ def run!
12
+ if @notes
13
+ @notes.each do |note|
14
+ system('clear')
15
+ polnote = Rmsgen::Inquirer.inquire_about_note(note)
16
+ write(polnote)
17
+ end
18
+ else
19
+ puts 'no polnotes in queue'
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def write(note)
26
+ if @output
27
+ File.open(@output, 'a') do |file|
28
+ file.puts note.to_html
29
+ end
30
+ else
31
+ puts note.to_html
32
+ puts
33
+ end
34
+ end
35
+
36
+ def fetch_notes
37
+ if @config['email_dir']
38
+ notes = Dir["#{@config['email_dir']}/*"].map { |f| File.read(f) }
39
+ else
40
+ notes = fetch_notes_from_imap
41
+ end
42
+ notes.map { |note| Rmsgen::Polnote.new(note) } if notes
43
+ end
44
+
45
+ def fetch_notes_from_imap
46
+ options = {
47
+ 'imap_login' => @config['imap_login'],
48
+ 'imap_password' => @config['imap_password']
49
+ }
50
+
51
+ imap = Net::IMAP.new(@config['imap_server'])
52
+ Rmsgen::IMAPPolnoteGroup.new(imap, options).fetch_notes
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,38 @@
1
+ module Rmsgen
2
+ class Script
3
+ def initialize(stdout=$stdout)
4
+ @stdout = stdout
5
+ end
6
+
7
+ def prompt_for_expiry_date
8
+ prompt "What day does it expire? ex) 08 July 2011:\n "
9
+ end
10
+
11
+ def prompt_for_text
12
+ prompt "What is the text?"
13
+ end
14
+
15
+ def prompt_for_polnote_link part
16
+ label = part[1..-2] + "?:\n"
17
+ prompt("What is the #{label}")
18
+ end
19
+
20
+ def prompt_for_title
21
+ prompt "Type title:"
22
+ end
23
+
24
+ def announce message
25
+ @stdout.puts message
26
+ @stdout.puts
27
+ end
28
+
29
+ private
30
+
31
+ def prompt(label)
32
+ announce label
33
+ input = $stdin.gets.chomp
34
+ @stdout.puts
35
+ input
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ module Rmsgen
2
+ class Titleizer
3
+ TEMPLATE = File.join(File.dirname(__FILE__), '..', 'templates', 'title.erb')
4
+
5
+ attr_reader :title
6
+
7
+ def initialize(polnote, options={})
8
+ @body = polnote.body
9
+ @title = options[:title]
10
+
11
+ @script = Script.new($stdout)
12
+ run!
13
+ end
14
+
15
+ def body
16
+ ERB.new(File.read(TEMPLATE)).result(binding)
17
+ end
18
+
19
+ def today_format
20
+ Date.today.strftime('%d %B %Y')
21
+ end
22
+
23
+ def today_underscore
24
+ today_format.gsub(' ', '_')
25
+ end
26
+
27
+ def title_underscore
28
+ @title.gsub(' ', '_')
29
+ end
30
+
31
+ def to_html
32
+ body
33
+ end
34
+
35
+ private
36
+
37
+ def run!
38
+ @title = @script.prompt_for_title unless @title
39
+ body
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ module Rmsgen
2
+ VERSION = "0.0.3"
3
+ end
data/lib/rmsgen.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+
4
+ module Rmsgen
5
+ %w{ part_group
6
+ polnote
7
+ titleizer
8
+ compresser
9
+ script
10
+ inquirer
11
+ runtime
12
+ link
13
+ imap_polnote_group
14
+ fs_polnote_group
15
+ }.each do |fname|
16
+ require File.join(File.dirname(__FILE__), 'rmsgen', fname)
17
+ end
18
+ end
19
+
20
+
21
+
@@ -0,0 +1,2 @@
1
+ <%= "<!-- Expires #{@expires_on} -->" if @expires_on %><%= @title %><% parts.map do |part| %><% if part =~ /<!--/ %><%= part %><% else %><p><%= part %></p><% end %>
2
+ <% end %>
@@ -0,0 +1 @@
1
+ <p><li><a name='<%= today_underscore %>_(<%= title_underscore %>)' /><%= today_format %> (<a class='titlelink' href='#<%= today_underscore %>_(<%= title_underscore %>)'><%= title %></a>)</p>
data/rmsgen.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rmsgen/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rmsgen"
7
+ s.version = Rmsgen::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Lake Denman"]
10
+ s.email = ["lake@lakedenman.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{A library to help generate html markup from RMS emails}
13
+ s.description = %q{A library to help generate html markup from RMS emails}
14
+
15
+ s.rubyforge_project = "rmsgen"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
data/spec/fake_gets.rb ADDED
@@ -0,0 +1,25 @@
1
+ class FakeGet
2
+ def initialize(input)
3
+ @in = input
4
+ end
5
+ def gets
6
+ @in
7
+ end
8
+ end
9
+
10
+ class FakeGetMany
11
+ attr_reader :answers
12
+
13
+ def initialize(*answers)
14
+ @answers = answers
15
+ end
16
+
17
+ def answer
18
+ @answers.shift
19
+ end
20
+
21
+ def gets
22
+ answer
23
+ end
24
+ end
25
+
@@ -0,0 +1,3 @@
1
+ hello
2
+
3
+ world
@@ -0,0 +1,7 @@
1
+ Somewhere over the rainbow.
2
+
3
+ http://rainbow.org
4
+
5
+ Skys are blue.
6
+
7
+ [Link to pol note]
@@ -0,0 +1,9 @@
1
+
2
+ Somewhere over the rainbow
3
+ skies are blue
4
+
5
+ http://unicorns.org
6
+
7
+ Candy is sweet
8
+ and unicorns are too
9
+
@@ -0,0 +1,39 @@
1
+ Return-Path: <rms@gnu.org>
2
+ X-Original-To: stallman-helpers@netpurgatory.com
3
+ Delivered-To: x12197960@homiemail-mx23.g.dreamhost.com
4
+ Received: from fencepost.gnu.org (fencepost.gnu.org [140.186.70.10])
5
+ (using TLSv1 with cipher AES256-SHA (256/256 bits))
6
+ (No client certificate requested)
7
+ by homiemail-mx23.g.dreamhost.com (Postfix) with ESMTPS id BF11A3E04EC;
8
+ Thu, 30 Jun 2011 17:18:49 -0700 (PDT)
9
+ Received: from rms by fencepost.gnu.org with local (Exim 4.71)
10
+ (envelope-from <rms@gnu.org>)
11
+ id 1QcRRV-0006Q7-4B; Thu, 30 Jun 2011 20:18:45 -0400
12
+ Date: Thu, 30 Jun 2011 20:18:45 -0400
13
+ Message-Id: <E1QcRRV-0006Q7-4B@fencepost.gnu.org>
14
+ Content-Type: text/plain; charset=ISO-8859-15
15
+ From: Richard Stallman <rms@gnu.org>
16
+ To: stallman-org@gnu.org
17
+ Subject: Urgent note
18
+ Reply-to: rms@gnu.org
19
+ Content-Length: 519
20
+
21
+ For one week:
22
+
23
+ US citizens: tell Obama to stand firm against Republican demands
24
+ for raising the debt ceiling.
25
+
26
+ http://
27
+
28
+ Once in a while, when enough people demand it, Obama does what he
29
+ ought to do.
30
+
31
+ --
32
+ Dr Richard Stallman
33
+ President, Free Software Foundation
34
+ 51 Franklin St
35
+ Boston MA 02110
36
+ USA
37
+ www.fsf.org www.gnu.org
38
+ Skype: No way! That's nonfree (freedom-denying) software.
39
+ Use free telephony http://directory.fsf.org/category/tel/
@@ -0,0 +1,37 @@
1
+ require 'rmsgen'
2
+
3
+ describe Rmsgen::FsPolnoteGroup do
4
+ context '.all' do
5
+ context 'when zero polnotes are in the directory' do
6
+ it 'returns an empty collection' do
7
+ empty_dir = 'empty-dir'
8
+ splat_dir = "#{empty_dir}/*"
9
+ Dir.should_receive(:[]).with(splat_dir).and_return([])
10
+ group = Rmsgen::FsPolnoteGroup.new(empty_dir)
11
+ result = group.all
12
+ result.should be_empty
13
+ end
14
+ end
15
+
16
+ context 'when one polnote is in the directory' do
17
+ let(:dir) { '/home/foo/dir' }
18
+ let(:splat_dir) { "#{dir}/*" }
19
+ let(:notes) { ['/home/foo/dir/polnote'] }
20
+
21
+ before do
22
+ Dir.should_receive(:[]).with(splat_dir).and_return(notes)
23
+ File.should_receive(:read).with(notes.first).and_return("hello world")
24
+ group = Rmsgen::FsPolnoteGroup.new(dir)
25
+ @result = group.all
26
+ end
27
+
28
+ it 'returns one element' do
29
+ @result.size.should == 1
30
+ end
31
+
32
+ it 'returns a polnote element' do
33
+ @result.first.should be_instance_of(Rmsgen::Polnote)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ require 'rmsgen'
2
+
3
+ describe Rmsgen::IMAPPolnoteGroup do
4
+ context 'fetching notes' do
5
+ let(:imap) { double('imap') }
6
+ let(:options) do {
7
+ 'imap_login' => 'login',
8
+ 'imap_password' => 'password'}
9
+ end
10
+
11
+ let(:do_fetch) do
12
+ imap.should_receive(:search).any_number_of_times
13
+ imap.should_receive(:authenticate).any_number_of_times
14
+ imap.should_receive(:select).any_number_of_times
15
+ Rmsgen::IMAPPolnoteGroup.new(imap, options).fetch_notes
16
+ end
17
+
18
+ it 'authenticates with imap server' do
19
+ imap.should_receive(:authenticate).any_number_of_times.with('LOGIN', 'login', 'password')
20
+ do_fetch
21
+ end
22
+
23
+ it 'selects the inbox folder' do
24
+ imap.should_receive(:select).any_number_of_times.with('INBOX')
25
+ do_fetch
26
+ end
27
+
28
+ it 'searches for messages from rms' do
29
+ imap.should_receive(:search).once.with(["FROM", 'rms@gnu.org'])
30
+ do_fetch
31
+ end
32
+
33
+ it 'fetches each message' do
34
+ message_id = double('message_id')
35
+ search_result = [message_id]
36
+
37
+ imap.stub(:search) { search_result }
38
+
39
+ imap.should_receive(:fetch).with(message_id, 'BODY[TEXT]')
40
+ do_fetch
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ require 'rmsgen'
2
+ require 'fake_gets'
3
+ require 'rspec'
4
+ require 'stringio'
5
+
6
+ describe Rmsgen::Inquirer do
7
+ let(:stdout) { StringIO.new }
8
+
9
+ describe "inquires about a note which is indented" do
10
+ let(:note) { Rmsgen::Polnote.new("foo\n\nhttp://\n\n bar") }
11
+
12
+ subject { Rmsgen::Inquirer.new(note, stdout) }
13
+
14
+ before do
15
+ $stdin = FakeGetMany.new("foo")
16
+ end
17
+
18
+ it "merges the url" do
19
+ exp = "<a href='http://'>foo</a> bar\n\n"
20
+ subject.body.should == exp
21
+ end
22
+ end
23
+
24
+ describe "it inquires about each link in a note" do
25
+ let(:note) { Rmsgen::Polnote.new("foo\n\nhttp://\n\nbar\n\nhttp://") }
26
+ subject { Rmsgen::Inquirer.new(note, stdout) }
27
+
28
+ before do
29
+ $stdin = FakeGetMany.new("foo", "bar")
30
+ end
31
+
32
+ it "inquires about each url" do
33
+ exp = "<a href='http://'>foo</a>\n\n<a href='http://'>bar</a>"
34
+ subject.body.should == exp
35
+ end
36
+ end
37
+
38
+ describe "inquiring about a duration" do
39
+ it "asks for the end date of the duration" do
40
+ note = Rmsgen::Polnote.new("For one week:\n\nUrgent: blah blah blah")
41
+ $stdin = FakeGetMany.new("July 1")
42
+ Rmsgen::Inquirer.new(note, stdout)
43
+ note.expires_on.should be == "July 1"
44
+ end
45
+ end
46
+
47
+ describe 'when a blank answer is given' do
48
+ it 'returns the polnote text without links' do
49
+ note = Rmsgen::Polnote.new("foo bar\n\nhttp://")
50
+ $stdin = FakeGetMany.new("")
51
+ inquirer = Rmsgen::Inquirer.new(note, stdout)
52
+ inquirer.body.should be == "foo bar"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,21 @@
1
+ require 'rmsgen'
2
+
3
+ describe PartGroup do
4
+ it "accepts text as input" do
5
+ input = "hello\n\nworld"
6
+ p = PartGroup.new(input)
7
+ p.text.should be == input
8
+ end
9
+
10
+ it "output list of parts ordered by appearance" do
11
+ input = "\n\n\n\n1\n\n2\n\n3\n\n4"
12
+ p = PartGroup.new(input)
13
+ p.should == ['1', '2', '3', '4']
14
+ end
15
+
16
+ it "splits input into parts based on carriage return and newline" do
17
+ input = "1\r\n\r\n2\r\n\r\n3\r\n\r\n4"
18
+ p = PartGroup.new(input)
19
+ p.should == ['1', '2', '3', '4']
20
+ end
21
+ end