rticles 0.1.0 → 0.2.1
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.
- 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.
|