rticles 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YmI4M2E4YzI3Mjg0ZTFjNzI3NmY0YzU5YjliYWY1MWM1Y2UwZGRmYw==
4
+ YTcxY2YyZTYxMTYwOGFlNmJjYmQzZjI0YzFiMThjYmNkYTdhOGQ4MA==
5
5
  data.tar.gz: !binary |-
6
- NGViZjgyMzQ2ZDJmN2Y3OWY4MzBkMTdhNjIyNDAzOTdlNTBlNjc0Ng==
7
- !binary "U0hBNTEy":
6
+ NGQ3NDk4MjhkMmY3NGVlODRlNTI1NDAyMjNlYjU4NDM2ZTcwNWVkNA==
7
+ SHA512:
8
8
  metadata.gz: !binary |-
9
- MTJjZGM1OGYzYTNhNDFhODJiMzc4YTQ4NWNiOTFhMTMzMzAzMTdhNDBmMzE2
10
- OWUwMThhYzEyNjA3YWU0NTMwNjk3ZGQ2ZDc0NWU3ZDlmMmU5YjU4NmJhNTE2
11
- ODI1ZGYyYmRmM2QyNzFhNTJlZWE5ZGYwMmZlZDExZjA1YjliY2M=
9
+ ZWI5MDU0NDhlNTFkMWZhMjc4YmM0MDQ3MTc2ZjBhNWQxYTNjMzgxNDZkYmY2
10
+ ZDZiMWU4MjBkNTVmNjdkMTI0OWNiYmM5YzE3MWU5NTMxM2RiOTVlZDc5MTRm
11
+ YjJiMGMxNzJkMWM0OTEyOGM2M2U5OTUwZWY0OWNlNTdjZWY5Mjc=
12
12
  data.tar.gz: !binary |-
13
- ZTNkZjU2YWEyZjIwM2IyNzUxOTJhOTc2MDgyZDNlNTFiYTQ3NjMwN2Q4NWYy
14
- NjM0ZThjNWIwZmFiYzkxODc1MmU0ZjAzNGMxNjE4ZWNiNjE2YmEyMTZhOGM2
15
- ZDFjYWJmYjBkZDcwZmE4ZTQzZmFkYzA0N2EyZjg3OTRiMWE0OWI=
13
+ NjRiZDc3YWE4MTc3NWZiOGJiNjQ4ZDJhNGVmNzQwMzA4NThkMTQyZmU4OTgy
14
+ MzI2ZGM1Yjg5YzE1ZmQ4Y2MxODM5MDU4NjIxZjZlNTgyOTE3Nzc0MTlkMGI1
15
+ ODhkMDFmMjU0MjdlZTgyZTRiZGI3ODA2ZGM4YzRiMmM2YjQwN2Y=
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ before_script:
6
+ "pushd spec/dummy && RAILS_ENV=test bundle exec rake db:create db:migrate; popd"
7
+ notifications:
8
+ recipients:
9
+ - alerts@oneclickorgs.com
data/README.md CHANGED
@@ -11,7 +11,7 @@ License
11
11
  Rticles is licensed under the [GNU Affero General Public License, Version 3](http://www.fsf.org/licensing/licenses/agpl-3.0.html).
12
12
 
13
13
  Rticles
14
- Copyright (C) 2011, 2012 Circus Foundation
14
+ Copyright (C) 2011, 2012, 2013 Circus Foundation
15
15
 
16
16
  This program is free software: you can redistribute it and/or modify
17
17
  it under the terms of the GNU Affero General Public License as
@@ -8,6 +8,7 @@ module Rticles
8
8
  TOPIC_RE = /\A#rticles#topic#([A-Za-z_]+) /
9
9
  CONTINUATION_RE = /\A#rticles#continue /
10
10
  HEADING_RE = /\A#rticles#heading(#\d+|) /
11
+ LIST_RE = /\A#rticles#list /
11
12
 
12
13
  has_many :paragraphs, :order => 'position'
13
14
  has_many :top_level_paragraphs, :class_name => 'Paragraph', :order => 'position', :conditions => "parent_id IS NULL"
@@ -42,19 +43,21 @@ module Rticles
42
43
  if body
43
44
  o.push(for_display ? tlp.body_for_display({:insertions => insertions, :choices => choices}.merge(options)) : tlp.body)
44
45
  unless tlp.children.empty?
45
- o.push(sub_outline(tlp, options))
46
+ o.push(sub_outline(tlp, options.merge(list: tlp.list?)))
46
47
  end
47
48
  end
48
49
  end
49
50
  o
50
51
  end
51
52
 
52
- def to_html
53
+ def to_html(options={})
53
54
  html = "<section>"
54
55
  html += Rticles::Paragraph.generate_html(top_level_paragraphs,
55
- :insertions => insertions,
56
- :choices => choices,
57
- :numbering_config => numbering_config
56
+ {
57
+ :insertions => insertions,
58
+ :choices => choices,
59
+ :numbering_config => numbering_config
60
+ }.merge(options)
58
61
  )
59
62
  html += "</section>"
60
63
  html.html_safe
@@ -81,6 +84,7 @@ module Rticles
81
84
  topic = nil
82
85
  continuation = false
83
86
  heading = nil
87
+ list = false
84
88
 
85
89
  if name_match = text_or_sub_array.match(NAME_RE)
86
90
  text_or_sub_array = text_or_sub_array.sub(NAME_RE, '')
@@ -105,13 +109,20 @@ module Rticles
105
109
  heading = heading_match[1].sub(/\A#/, '').to_i
106
110
  end
107
111
  end
112
+
113
+ if text_or_sub_array.match(LIST_RE)
114
+ text_or_sub_array = text_or_sub_array.sub(LIST_RE, '')
115
+ list = true
116
+ end
117
+
108
118
  document.paragraphs.create(
109
119
  :parent_id => parent ? parent.id : nil,
110
120
  :body => text_or_sub_array,
111
121
  :name => name,
112
122
  :topic => topic,
113
123
  :heading => heading,
114
- :continuation => continuation
124
+ :continuation => continuation,
125
+ :list => list
115
126
  )
116
127
  when Array
117
128
  paragraphs_relation = parent ? parent.children : document.paragraphs.select{|p| p.parent_id.nil?}
@@ -134,9 +145,21 @@ module Rticles
134
145
  end
135
146
 
136
147
  def paragraph_numbers_for_topic(topic, consolidate=false)
137
- relevant_paragraphs = paragraphs.where(:topic => topic)
148
+ paragraph_numbers_for_topics([topic], consolidate)
149
+ end
150
+
151
+ def paragraph_numbers_for_topics(topics, consolidate=false)
152
+ relevant_paragraphs = paragraphs.where(:topic => topics)
138
153
  relevant_paragraphs = relevant_paragraphs.for_choices(choices)
139
- paragraph_numbers = relevant_paragraphs.map{|p| p.full_index(true, choices)}.select{|i| !i.nil?}.sort
154
+ # TODO Sorting by position won't work properly if the query includes
155
+ # sub-paragraphs, but it is fine for the common case where only
156
+ # top-level paragraphs have topics.
157
+ # We should really be sorting by full_index, but
158
+ # we don't have a sort function for this yet. (A naive typographical
159
+ # sort isn't good enough.)
160
+ relevant_paragraphs = relevant_paragraphs.order('position ASC')
161
+
162
+ paragraph_numbers = relevant_paragraphs.map{|p| p.full_index(true, choices)}.select{|i| !i.nil?}
140
163
 
141
164
  if consolidate
142
165
  consolidate_paragraph_numbers(paragraph_numbers)
@@ -152,7 +175,7 @@ module Rticles
152
175
  protected
153
176
 
154
177
  def consolidate_paragraph_numbers(numbers)
155
- numbers = numbers.sort
178
+ # numbers = numbers.sort
156
179
  consolidated_numbers = []
157
180
  current_run = []
158
181
  numbers.each do |n|
@@ -185,7 +208,8 @@ module Rticles
185
208
  for_display = options[:for_display]
186
209
 
187
210
  o = []
188
- p.children.each do |c|
211
+ last_index = p.children.length - 1
212
+ p.children.each_with_index do |c, index|
189
213
  body = for_display ? c.body_for_display({:insertions => insertions, :choices => choices}.merge(options)) : c.body
190
214
  if body
191
215
  o.push(body)
@@ -194,6 +218,20 @@ module Rticles
194
218
  end
195
219
  end
196
220
  end
221
+ if options[:list]
222
+ # Add terminating punctuation to the String elements of o, but making the last one a full stop instead of a semicolon.
223
+ final_element = true
224
+ o.reverse_each do |p|
225
+ if p.is_a?(String)
226
+ if final_element
227
+ p.sub!(/\Z/, '.')
228
+ final_element = false
229
+ else
230
+ p.sub!(/\Z/, ';')
231
+ end
232
+ end
233
+ end
234
+ end
197
235
  o
198
236
  end
199
237
  end
@@ -12,6 +12,7 @@ module Rticles
12
12
 
13
13
  def create_migration
14
14
  migration_template 'create_documents_and_paragraphs.rb', 'db/migrate/create_documents_and_paragraphs.rb'
15
+ migration_template 'add_list_to_paragraphs.rb', 'db/migrate/add_list_to_paragraphs.rb'
15
16
  end
16
17
  end
17
18
  end
@@ -0,0 +1,9 @@
1
+ class AddListToParagraphs < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :paragraphs, :list, :boolean
4
+ end
5
+
6
+ def self.down
7
+ remove_column :paragraphs, :list
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Rticles
2
+ module Generators
3
+ class UpdateGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def self.next_migration_number(dirname)
9
+ next_migration_number = current_migration_number(dirname) + 1
10
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
11
+ end
12
+
13
+ def create_migration
14
+ migration_template 'add_list_to_paragraphs.rb', 'db/migrate/add_list_to_paragraphs.rb'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,7 +3,9 @@ require 'acts_as_list'
3
3
  module Rticles
4
4
  class Paragraph < ActiveRecord::Base
5
5
  attr_accessible :body, :parent_id, :after_id, :position, :before_id, :heading, :continuation,
6
- :name, :topic
6
+ :name, :topic, :list
7
+
8
+ attr_writer :choices
7
9
 
8
10
  belongs_to :document
9
11
  belongs_to :parent, :class_name => 'Paragraph'
@@ -14,7 +16,7 @@ module Rticles
14
16
  scope :for_choices, lambda {|choices|
15
17
  choices_condition = ["", {}]
16
18
  choices.each do |k, v|
17
- choices_condition[0] += "AND body NOT LIKE :#{k}"
19
+ choices_condition[0] += "AND body NOT LIKE :#{k} "
18
20
  choices_condition[1][k.to_sym] = "#rticles##{v ? 'false' : 'true'}##{k}%"
19
21
  end
20
22
  choices_condition[0].sub!(/\AAND /, '')
@@ -206,7 +208,7 @@ module Rticles
206
208
  string.gsub(insertion_re) do |match|
207
209
  insertion_name = match.sub('#rticles#', '')
208
210
  if insertions[insertion_name].present?
209
- insertions[insertion_name]
211
+ insertions[insertion_name].to_s.gsub("\n", "<br>")
210
212
  else
211
213
  "[#{insertion_name.humanize.upcase}]"
212
214
  end
@@ -249,11 +251,36 @@ module Rticles
249
251
 
250
252
  def self.generate_html_for_paragraph_groups(paragraph_groups, options={})
251
253
  previous_type = nil
252
- html = paragraph_groups.inject("") do |memo, paragraph_group|
254
+
255
+ # Remove paragraph groups that should not be displayed, given the choices that have been passed in
256
+ paragraph_groups = paragraph_groups.map do |pg|
257
+ first_paragraph = pg[0]
258
+ first_paragraph.choices = options[:choices]
259
+ if first_paragraph.resolve_choices(first_paragraph.body)
260
+ pg
261
+ else
262
+ nil
263
+ end
264
+ end
265
+ paragraph_groups = paragraph_groups.compact
266
+
267
+ # Handle last paragraph group separately so we can do list punctuation if necessary.
268
+
269
+ paragraph_groups_except_last = paragraph_groups[0..-2]
270
+ last_paragraph_group = paragraph_groups[-1]
271
+
272
+ html = paragraph_groups_except_last.inject("") do |memo, paragraph_group|
253
273
  # FIXME: Don't generate HTML by interpolating into a string;
254
274
  # use some standard library function that provides some safe
255
275
  # escaping defaults, etc..
256
- if paragraph_group.first.heading?
276
+
277
+ if options[:list]
278
+ options[:list_punctuation] = ';'
279
+ end
280
+
281
+ first_paragraph = paragraph_group[0]
282
+
283
+ if first_paragraph.heading?
257
284
  if previous_type == :paragraph
258
285
  memo += "</ol>"
259
286
  end
@@ -267,11 +294,42 @@ module Rticles
267
294
  unless previous_type == :paragraph
268
295
  memo += "<ol>"
269
296
  end
270
- memo += "<li>#{generate_html_for_paragraphs(paragraph_group, options)}</li>"
297
+ index = first_paragraph.index(options[:choices])
298
+ li_opening_tag = "<li value=\"#{index}\">"
299
+ memo += "#{li_opening_tag}#{generate_html_for_paragraphs(paragraph_group, options)}</li>"
271
300
  previous_type = :paragraph
272
301
  end
302
+
273
303
  memo
274
304
  end
305
+
306
+ # Process final paragraph group
307
+ if options[:list]
308
+ options[:list_punctuation] = '.'
309
+ end
310
+
311
+ first_paragraph = last_paragraph_group[0]
312
+
313
+ if first_paragraph.heading?
314
+ if previous_type == :paragraph
315
+ html += "</ol>"
316
+ end
317
+ if last_paragraph_group.length == 1
318
+ html += generate_html_for_paragraphs(last_paragraph_group, options)
319
+ else
320
+ html += "<hgroup>#{generate_html_for_paragraphs(last_paragraph_group, options)}</hgroup>"
321
+ end
322
+ previous_type = :heading
323
+ else
324
+ unless previous_type == :paragraph
325
+ html += "<ol>"
326
+ end
327
+ index = first_paragraph.index(options[:choices])
328
+ li_opening_tag = "<li value=\"#{index}\">"
329
+ html += "#{li_opening_tag}#{generate_html_for_paragraphs(last_paragraph_group, options)}</li>"
330
+ previous_type = :paragraph
331
+ end
332
+
275
333
  if previous_type == :paragraph
276
334
  html += "</ol>"
277
335
  end
@@ -283,13 +341,13 @@ module Rticles
283
341
  return memo if body.nil?
284
342
 
285
343
  if paragraph.heading?
286
- memo += "<h#{paragraph.heading_level}>#{body}</h#{paragraph.heading_level}>"
344
+ memo += "<h#{paragraph.heading_level}>#{body}#{options[:list_punctuation]}</h#{paragraph.heading_level}>"
287
345
  else
288
- memo += body
346
+ memo += "#{body}#{options[:list_punctuation]}"
289
347
  end
290
348
 
291
349
  if !paragraph.children.empty?
292
- memo += generate_html(paragraph.children, options)
350
+ memo += generate_html(paragraph.children, options.merge(list: paragraph.list?, list_punctuation: nil))
293
351
  end
294
352
  memo
295
353
  end
@@ -1,5 +1,6 @@
1
1
  class Rticles::Railtie < Rails::Railtie
2
2
  generators do
3
3
  require 'rticles/generators/install_generator'
4
+ require 'rticles/generators/update_generator'
4
5
  end
5
6
  end
@@ -1,3 +1,3 @@
1
1
  module Rticles
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -12,15 +12,17 @@ Gem::Specification.new do |s|
12
12
  s.homepage = "https://github.com/oneclickorgs/rticles"
13
13
  s.summary = "Consistent editing for legal documents."
14
14
  s.description = "Rticles is a Rails plugin that allows for web-based editing of legal documents. It lets you create nested, numbered paragraphs, along with intra-document references that remain accurate as paragraphs are inserted, removed and moved."
15
+ s.licenses = ['AGPL-3']
15
16
 
16
17
  s.files = `git ls-files`.split($\)
17
18
 
18
19
  s.add_dependency "rails", "~> 3.2.8"
19
- s.add_dependency "acts_as_list", "~>0.1.8"
20
+ s.add_dependency "acts_as_list", ">=0.1.8", "<0.3.0"
20
21
  s.add_dependency "roman-numerals", "~>0.3.0"
21
22
 
22
23
  s.add_development_dependency "sqlite3"
23
24
  s.add_development_dependency "rspec-rails"
24
25
  s.add_development_dependency "nokogiri"
25
26
  s.add_development_dependency "equivalent-xml"
27
+ s.add_development_dependency "coveralls"
26
28
  end
@@ -124,6 +124,73 @@ describe Rticles::Document do
124
124
  end
125
125
  end
126
126
 
127
+ describe "list punctuation" do
128
+ before(:each) do
129
+ yaml = File.open('spec/fixtures/list_termination.yml', 'r')
130
+ @document = Rticles::Document.from_yaml(yaml)
131
+ @document.save!
132
+
133
+ @document.choices = {
134
+ users: true,
135
+ employees: true,
136
+ supporters: true,
137
+ }
138
+ end
139
+
140
+ it "punctuates lists of sub-clauses correctly when all sub-clauses are present" do
141
+ expect(@document.outline(for_display: true)).to eq([
142
+ "The Board shall consist of:",
143
+ [
144
+ "Users;",
145
+ "Employees;",
146
+ "Supporters."
147
+ ]
148
+ ])
149
+ end
150
+
151
+ it "punctuates lists of sub-clauses correctly when some sub-clauses are omitted" do
152
+ @document.choices = {
153
+ users: true,
154
+ employees: true,
155
+ supporters: false
156
+ }
157
+
158
+ expect(@document.outline(for_display: true)).to eq([
159
+ "The Board shall consist of:",
160
+ [
161
+ "Users;",
162
+ "Employees."
163
+ ]
164
+ ])
165
+ end
166
+
167
+ it "punctuates lists correctly when generating HTML" do
168
+ @document.choices = {
169
+ users: true,
170
+ employees: true,
171
+ supporters: false
172
+ }
173
+
174
+ expected_html = <<-EOF
175
+ <section>
176
+ <ol>
177
+ <li value="1">
178
+ The Board shall consist of:
179
+ <ol>
180
+ <li value="1">Users;</li>
181
+ <li value="2">Employees.</li>
182
+ </ol>
183
+ </li>
184
+ </ol>
185
+ </section>
186
+ EOF
187
+
188
+ html = @document.to_html(with_index: false)
189
+
190
+ expect(html).to be_equivalent_to(expected_html)
191
+ end
192
+ end
193
+
127
194
  describe "topic lookup" do
128
195
  it "takes into account the current choices" do
129
196
  @document = Rticles::Document.create
@@ -151,6 +218,17 @@ describe Rticles::Document do
151
218
  @document.choices[:single_shareholding] = false
152
219
  @document.paragraph_numbers_for_topic('shares', true).should eq "35–40"
153
220
  end
221
+
222
+ it "can handle multiple topics" do
223
+ @document = Rticles::Document.create
224
+ @document.top_level_paragraphs.create(:body => "First shares rule", :topic => 'shares')
225
+ @document.top_level_paragraphs.create(:body => "Objectives rule", :topic => 'objectives')
226
+ @document.top_level_paragraphs.create(:body => "Other rule")
227
+ @document.top_level_paragraphs.create(:body => "Second shares rule", :topic => 'shares')
228
+
229
+ @document.paragraph_numbers_for_topics(['shares', 'objectives'], true).should eq '1–2, 4'
230
+ end
231
+
154
232
  end
155
233
 
156
234
  describe "numbering config" do
@@ -4,7 +4,7 @@
4
4
  = content_tag("h#{paragraph.heading_level}") do
5
5
  = paragraph.body_for_display
6
6
  - else
7
- = simple_format(paragraph.full_index + ' ' + paragraph.body_for_display)
7
+ = simple_format((paragraph.full_index || '') + ' ' + (paragraph.body_for_display || ''))
8
8
  - if @editing
9
9
  %p.control
10
10
  = link_to "Edit", edit_document_paragraph_path(:document_id => paragraph.document, :id => paragraph), :class => 'edit_paragraph'
@@ -1,6 +1,6 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
3
+ Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session'
4
4
 
5
5
  # Use the database for sessions instead of the cookie-based default,
6
6
  # which shouldn't be used to store highly confidential information
@@ -5,7 +5,7 @@
5
5
 
6
6
  # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
7
  ActiveSupport.on_load(:action_controller) do
8
- wrap_parameters format: [:json]
8
+ wrap_parameters :format => [:json]
9
9
  end
10
10
 
11
11
  # Disable root element in JSON by default.
@@ -0,0 +1,9 @@
1
+ class AddListToParagraphs < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :paragraphs, :list, :boolean
4
+ end
5
+
6
+ def self.down
7
+ remove_column :paragraphs, :list
8
+ end
9
+ end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20120828203449) do
14
+ ActiveRecord::Schema.define(:version => 20140112165306) do
15
15
 
16
16
  create_table "documents", :force => true do |t|
17
17
  t.string "title"
@@ -30,6 +30,7 @@ ActiveRecord::Schema.define(:version => 20120828203449) do
30
30
  t.string "topic"
31
31
  t.datetime "created_at", :null => false
32
32
  t.datetime "updated_at", :null => false
33
+ t.boolean "list"
33
34
  end
34
35
 
35
36
  end
@@ -0,0 +1,5 @@
1
+ - "#rticles#list The Board shall consist of:"
2
+ -
3
+ - "#rticles#true#users Users"
4
+ - "#rticles#true#employees Employees"
5
+ - "#rticles#true#supporters Supporters"
@@ -224,21 +224,21 @@ describe Rticles::Paragraph do
224
224
  <h2>For demonstration purposes only</h2>
225
225
  </hgroup>
226
226
  <ol>
227
- <li>1 This is the first rule.</li>
228
- <li>
227
+ <li value="1">1 This is the first rule.</li>
228
+ <li value="2">
229
229
  2 This is the second rule, which applies when:
230
230
  <ol>
231
- <li>2.1 This condition;</li>
232
- <li>2.2 and this condition.</li>
231
+ <li value="1">2.1 This condition;</li>
232
+ <li value="2">2.2 and this condition.</li>
233
233
  </ol>
234
234
  except when it is a Full Moon.
235
235
  </li>
236
- <li>3 This is the third rule.</li>
237
- <li>4 This is the fourth rule.</li>
236
+ <li value="3">3 This is the third rule.</li>
237
+ <li value="4">4 This is the fourth rule.</li>
238
238
  </ol>
239
239
  <h2>And finally...</h2>
240
240
  <ol>
241
- <li>5 This is the final rule.</li>
241
+ <li value="5">5 This is the final rule.</li>
242
242
  </ol>
243
243
  </section>
244
244
  EOF
@@ -247,5 +247,159 @@ describe Rticles::Paragraph do
247
247
 
248
248
  html.should be_equivalent_to(expected_html)
249
249
  end
250
+
251
+ context "with insertions" do
252
+ it "converts newlines into br tags" do
253
+ @document.top_level_paragraphs.create(
254
+ :body => "A custom rule is: #rticles#custom_rule",
255
+ :after_id => @document.top_level_paragraphs.all[4].id
256
+ )
257
+
258
+ expected_html = <<-EOF
259
+ <section>
260
+ <hgroup>
261
+ <h1>A Simple Constitution</h1>
262
+ <h2>For demonstration purposes only</h2>
263
+ </hgroup>
264
+ <ol>
265
+ <li value="1">1 This is the first rule.</li>
266
+ <li value="2">
267
+ 2 This is the second rule, which applies when:
268
+ <ol>
269
+ <li value="1">2.1 This condition;</li>
270
+ <li value="2">2.2 and this condition.</li>
271
+ </ol>
272
+ except when it is a Full Moon.
273
+ </li>
274
+ <li value="3">3 A custom rule is: I can format my clauses<br>how I<br>please.</li>
275
+ <li value="4">4 This is the third rule.</li>
276
+ <li value="5">5 This is the fourth rule.</li>
277
+ </ol>
278
+ <h2>And finally...</h2>
279
+ <ol>
280
+ <li value="6">6 This is the final rule.</li>
281
+ </ol>
282
+ </section>
283
+ EOF
284
+
285
+ @document.insertions = {:custom_rule => "I can format my clauses\nhow I\nplease."}
286
+
287
+ html = @document.to_html
288
+
289
+ html.should be_equivalent_to(expected_html)
290
+ end
291
+ end
292
+
293
+ context "with choices" do
294
+ before(:each) do
295
+ @document.top_level_paragraphs.create(
296
+ :body => "#rticles#true#free_cake All members shall be entitled to free cake",
297
+ :after_id => @document.top_level_paragraphs.all[4].id
298
+ )
299
+ end
300
+
301
+ it "includes the 'true' clause when the choice is set to true" do
302
+ expected_html = <<-EOF
303
+ <section>
304
+ <hgroup>
305
+ <h1>A Simple Constitution</h1>
306
+ <h2>For demonstration purposes only</h2>
307
+ </hgroup>
308
+ <ol>
309
+ <li value="1">1 This is the first rule.</li>
310
+ <li value="2">
311
+ 2 This is the second rule, which applies when:
312
+ <ol>
313
+ <li value="1">2.1 This condition;</li>
314
+ <li value="2">2.2 and this condition.</li>
315
+ </ol>
316
+ except when it is a Full Moon.
317
+ </li>
318
+ <li value="3">3 All members shall be entitled to free cake</li>
319
+ <li value="4">4 This is the third rule.</li>
320
+ <li value="5">5 This is the fourth rule.</li>
321
+ </ol>
322
+ <h2>And finally...</h2>
323
+ <ol>
324
+ <li value="6">6 This is the final rule.</li>
325
+ </ol>
326
+ </section>
327
+ EOF
328
+
329
+ @document.choices = {:free_cake => true}
330
+
331
+ html = @document.to_html
332
+
333
+ html.should be_equivalent_to(expected_html)
334
+ end
335
+
336
+ it "excludes the 'true' clause when the choice is set to false" do
337
+ expected_html = <<-EOF
338
+ <section>
339
+ <hgroup>
340
+ <h1>A Simple Constitution</h1>
341
+ <h2>For demonstration purposes only</h2>
342
+ </hgroup>
343
+ <ol>
344
+ <li value="1">1 This is the first rule.</li>
345
+ <li value="2">
346
+ 2 This is the second rule, which applies when:
347
+ <ol>
348
+ <li value="1">2.1 This condition;</li>
349
+ <li value="2">2.2 and this condition.</li>
350
+ </ol>
351
+ except when it is a Full Moon.
352
+ </li>
353
+ <li value="3">3 This is the third rule.</li>
354
+ <li value="4">4 This is the fourth rule.</li>
355
+ </ol>
356
+ <h2>And finally...</h2>
357
+ <ol>
358
+ <li value="5">5 This is the final rule.</li>
359
+ </ol>
360
+ </section>
361
+ EOF
362
+
363
+ @document.choices = {:free_cake => false}
364
+
365
+ html = @document.to_html
366
+
367
+ html.should be_equivalent_to(expected_html)
368
+ end
369
+ end
370
+
371
+ context "without indexes" do
372
+ it "works" do
373
+ expected_html = <<-EOF
374
+ <section>
375
+ <hgroup>
376
+ <h1>A Simple Constitution</h1>
377
+ <h2>For demonstration purposes only</h2>
378
+ </hgroup>
379
+ <ol>
380
+ <li value="1">This is the first rule.</li>
381
+ <li value="2">
382
+ This is the second rule, which applies when:
383
+ <ol>
384
+ <li value="1">This condition;</li>
385
+ <li value="2">and this condition.</li>
386
+ </ol>
387
+ except when it is a Full Moon.
388
+ </li>
389
+ <li value="3">This is the third rule.</li>
390
+ <li value="4">This is the fourth rule.</li>
391
+ </ol>
392
+ <h2>And finally...</h2>
393
+ <ol>
394
+ <li value="5">This is the final rule.</li>
395
+ </ol>
396
+ </section>
397
+ EOF
398
+
399
+ html = @document.to_html(:with_index => false)
400
+
401
+ html.should be_equivalent_to(expected_html)
402
+ end
403
+ end
250
404
  end
251
405
  end
@@ -1,3 +1,6 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
1
4
  # This file is copied to spec/ when you run 'rails generate rspec:install'
2
5
  ENV["RAILS_ENV"] ||= 'test'
3
6
  require File.expand_path("../dummy/config/environment", __FILE__)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rticles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Mear
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-01 00:00:00.000000000 Z
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -28,16 +28,22 @@ dependencies:
28
28
  name: acts_as_list
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - ! '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.1.8
34
+ - - <
35
+ - !ruby/object:Gem::Version
36
+ version: 0.3.0
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - ~>
41
+ - - ! '>='
39
42
  - !ruby/object:Gem::Version
40
43
  version: 0.1.8
44
+ - - <
45
+ - !ruby/object:Gem::Version
46
+ version: 0.3.0
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: roman-numerals
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +114,20 @@ dependencies:
108
114
  - - ! '>='
109
115
  - !ruby/object:Gem::Version
110
116
  version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: coveralls
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
111
131
  description: Rticles is a Rails plugin that allows for web-based editing of legal
112
132
  documents. It lets you create nested, numbered paragraphs, along with intra-document
113
133
  references that remain accurate as paragraphs are inserted, removed and moved.
@@ -119,6 +139,7 @@ extra_rdoc_files: []
119
139
  files:
120
140
  - .gitignore
121
141
  - .rspec
142
+ - .travis.yml
122
143
  - Gemfile
123
144
  - Gemfile.lock
124
145
  - LICENSE.txt
@@ -128,7 +149,9 @@ files:
128
149
  - lib/rticles.rb
129
150
  - lib/rticles/document.rb
130
151
  - lib/rticles/generators/install_generator.rb
152
+ - lib/rticles/generators/templates/add_list_to_paragraphs.rb
131
153
  - lib/rticles/generators/templates/create_documents_and_paragraphs.rb
154
+ - lib/rticles/generators/update_generator.rb
132
155
  - lib/rticles/numbering.rb
133
156
  - lib/rticles/paragraph.rb
134
157
  - lib/rticles/railtie.rb
@@ -179,6 +202,7 @@ files:
179
202
  - spec/dummy/config/locales/en.yml
180
203
  - spec/dummy/config/routes.rb
181
204
  - spec/dummy/db/migrate/20120828203449_create_documents_and_paragraphs.rb
205
+ - spec/dummy/db/migrate/20140112165306_add_list_to_paragraphs.rb
182
206
  - spec/dummy/db/schema.rb
183
207
  - spec/dummy/lib/assets/.gitkeep
184
208
  - spec/dummy/log/.gitkeep
@@ -189,13 +213,15 @@ files:
189
213
  - spec/dummy/script/rails
190
214
  - spec/fixtures/constitution.yml
191
215
  - spec/fixtures/ips.yml
216
+ - spec/fixtures/list_termination.yml
192
217
  - spec/fixtures/simple.yml
193
218
  - spec/paragraph_spec.rb
194
219
  - spec/spec_helper.rb
195
220
  - spec/support/custom_matchers.rb
196
221
  - spec/support/document_macros.rb
197
222
  homepage: https://github.com/oneclickorgs/rticles
198
- licenses: []
223
+ licenses:
224
+ - AGPL-3
199
225
  metadata: {}
200
226
  post_install_message:
201
227
  rdoc_options: []
@@ -213,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
239
  version: '0'
214
240
  requirements: []
215
241
  rubyforge_project:
216
- rubygems_version: 2.0.3
242
+ rubygems_version: 2.2.2
217
243
  signing_key:
218
244
  specification_version: 4
219
245
  summary: Consistent editing for legal documents.