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 +9 -9
- data/.travis.yml +9 -0
- data/README.md +1 -1
- data/lib/rticles/document.rb +48 -10
- data/lib/rticles/generators/install_generator.rb +1 -0
- data/lib/rticles/generators/templates/add_list_to_paragraphs.rb +9 -0
- data/lib/rticles/generators/update_generator.rb +18 -0
- data/lib/rticles/paragraph.rb +67 -9
- data/lib/rticles/railtie.rb +1 -0
- data/lib/rticles/version.rb +1 -1
- data/rticles.gemspec +3 -1
- data/spec/document_spec.rb +78 -0
- data/spec/dummy/app/views/paragraphs/_paragraph_internal.html.haml +1 -1
- data/spec/dummy/config/initializers/session_store.rb +1 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +1 -1
- data/spec/dummy/db/migrate/20140112165306_add_list_to_paragraphs.rb +9 -0
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/fixtures/list_termination.yml +5 -0
- data/spec/paragraph_spec.rb +161 -7
- data/spec/spec_helper.rb +3 -0
- metadata +32 -6
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTcxY2YyZTYxMTYwOGFlNmJjYmQzZjI0YzFiMThjYmNkYTdhOGQ4MA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
7
|
-
|
6
|
+
NGQ3NDk4MjhkMmY3NGVlODRlNTI1NDAyMjNlYjU4NDM2ZTcwNWVkNA==
|
7
|
+
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWI5MDU0NDhlNTFkMWZhMjc4YmM0MDQ3MTc2ZjBhNWQxYTNjMzgxNDZkYmY2
|
10
|
+
ZDZiMWU4MjBkNTVmNjdkMTI0OWNiYmM5YzE3MWU5NTMxM2RiOTVlZDc5MTRm
|
11
|
+
YjJiMGMxNzJkMWM0OTEyOGM2M2U5OTUwZWY0OWNlNTdjZWY5Mjc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NjRiZDc3YWE4MTc3NWZiOGJiNjQ4ZDJhNGVmNzQwMzA4NThkMTQyZmU4OTgy
|
14
|
+
MzI2ZGM1Yjg5YzE1ZmQ4Y2MxODM5MDU4NjIxZjZlNTgyOTE3Nzc0MTlkMGI1
|
15
|
+
ODhkMDFmMjU0MjdlZTgyZTRiZGI3ODA2ZGM4YzRiMmM2YjQwN2Y=
|
data/.travis.yml
ADDED
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
|
data/lib/rticles/document.rb
CHANGED
@@ -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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
@@ -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
|
data/lib/rticles/paragraph.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/rticles/railtie.rb
CHANGED
data/lib/rticles/version.rb
CHANGED
data/rticles.gemspec
CHANGED
@@ -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", "
|
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
|
data/spec/document_spec.rb
CHANGED
@@ -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
|
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
|
8
|
+
wrap_parameters :format => [:json]
|
9
9
|
end
|
10
10
|
|
11
11
|
# Disable root element in JSON by default.
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -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 =>
|
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
|
data/spec/paragraph_spec.rb
CHANGED
@@ -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
|
data/spec/spec_helper.rb
CHANGED
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
|
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:
|
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.
|
242
|
+
rubygems_version: 2.2.2
|
217
243
|
signing_key:
|
218
244
|
specification_version: 4
|
219
245
|
summary: Consistent editing for legal documents.
|