law_doc 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,318 @@
1
+ module LawDoc
2
+ class Case
3
+ STYLES = %i[versus inre].freeze
4
+
5
+ attr_reader :number, :complaint_date, :style, :court,
6
+ :judge, :magistrate, :parties
7
+
8
+ include InitTypes
9
+
10
+ def initialize(number: nil,
11
+ complaint_date: nil,
12
+ style: :versus,
13
+ court: nil,
14
+ judge: nil,
15
+ magistrate: nil,
16
+ parties: [])
17
+ @number = number.to_s
18
+ @complaint_date = init_date(complaint_date, field: 'complaint_date')
19
+ @court = init_court(court)
20
+ @judge = init_judge(judge)
21
+ @magistrate = init_judge(magistrate, field: 'magistrate') if magistrate
22
+ if style
23
+ @style = style.to_s.to_sym
24
+ raise "invalid Case style: '#{@style}'" unless STYLES.include?(@style)
25
+ end
26
+ @parties = init_parties(parties)
27
+ end
28
+
29
+ def to_s
30
+ number
31
+ end
32
+
33
+ def to_h
34
+ { number: number, complaint_date: complaint_date,
35
+ style: style, court: court.to_h, judge: judge.to_h,
36
+ magistrate: magistrate.to_h,
37
+ parties: parties }
38
+ end
39
+
40
+ include Comparable
41
+
42
+ def <=>(other)
43
+ to_h <=> other.to_h
44
+ end
45
+
46
+ # Return an array of parties that are plaintiffs. Any party whose role
47
+ # contains 'plaintiff' counts.
48
+ def plaintiffs
49
+ result = parties_of_role('plaintiff')
50
+ parties_matching_role(/plaintiff/i).each do |pty|
51
+ result << pty unless result.include?(pty)
52
+ end
53
+ result
54
+ end
55
+
56
+ # Return the first party that is a plaintiff.
57
+ def plaintiff
58
+ plaintiffs.first
59
+ end
60
+
61
+ # Return an array of parties that are defendants. Any party whose role
62
+ # contains 'defendant' counts.
63
+ def defendants
64
+ result = parties_of_role('defendant')
65
+ parties_matching_role(/defendant/i).each do |pty|
66
+ result << pty unless result.include?(pty)
67
+ end
68
+ result
69
+ end
70
+
71
+ # Return the first party that is a defendant.
72
+ def defendant
73
+ defendants.first
74
+ end
75
+
76
+ # Return an array of parties that are neither plaintiffs nor defendants.
77
+ def other_parties
78
+ result = Set.new(parties)
79
+ result -= plaintiffs
80
+ result -= defendants
81
+ result.to_a
82
+ end
83
+
84
+ def parties_of_lawyer(lwy)
85
+ parties.select { |pty| pty.lawyers.include?(lwy) }
86
+ end
87
+
88
+ def lawyer_parties_names(lwy)
89
+ parties_of_lawyer(lwy).map(&:name).join_and
90
+ end
91
+
92
+ def lawyer_roles(lwy)
93
+ ptys = parties_of_lawyer(lwy)
94
+ role = ptys.first.role
95
+ if ptys.size == 1
96
+ role.singularize
97
+ else
98
+ role.pluralize
99
+ end
100
+ end
101
+
102
+ # Return an array of the parties for this case whose role attribute exactly
103
+ # equals the parameter role.
104
+ def parties_of_role(role)
105
+ role = role.to_s.singularize.downcase
106
+ parties.select { |p| p.role.downcase == role }
107
+ end
108
+
109
+ # Return an array of the parties for this case whose role attribute does
110
+ # /not/ equal the parameter role.
111
+ def parties_not_role(role)
112
+ role = role.to_s.singularize.downcase
113
+ parties.reject { |p| p.role.downcase == role }
114
+ end
115
+
116
+ # Return an array of the parties for this case whose role matches the regexp
117
+ # given by role, either as a literal Regexp or as a String converted to a
118
+ # Regexp. In the latter case, unless the string starts and ends with '/'
119
+ # any Regexp meta-characters in the string are quoted. Matches are done
120
+ # case insensitively against each party's 'role' attribute. Since each
121
+ # party's role will be expressed in the singular form, we singularize before
122
+ # matching against individual parties. Thus, 'plaintiffs' will match all
123
+ # parties with role 'Plaintiff'.
124
+ def parties_matching_role(role)
125
+ match_role =
126
+ case role
127
+ when Regexp
128
+ role
129
+ when String
130
+ if role =~ %r{\A/([^/]*)/\z}
131
+ Regexp.new($1.singularize)
132
+ else
133
+ Regexp.new(Regexp.quote(role.singularize), true)
134
+ end
135
+ else
136
+ raise ArgumentError, 'role parameter must be Regexp or String'
137
+ end
138
+ parties.select { |p| p.role.downcase =~ match_role }
139
+ end
140
+
141
+ # Return an array of the parties for this case whose role does /not/ match
142
+ # the regexp given by role, either as a literal Regexp or as a String
143
+ # converted to a Regexp. In the latter case, unless the string starts and
144
+ # ends with '/' any Regexp meta-characters in the string are quoted. Matches
145
+ # are done case insensitively against each party's 'role' attribute.
146
+ def parties_not_matching_role(role)
147
+ role =
148
+ case role
149
+ when Regexp
150
+ role
151
+ when String
152
+ role =
153
+ if role =~ %r{\A/([^/]*)/\z}
154
+ Regexp.new($1)
155
+ else
156
+ Regexp.new(Regexp.quote(role), true)
157
+ end
158
+ else
159
+ raise ArgumentError, 'role parameter must be Regexp or String'
160
+ end
161
+ parties.reject { |p| p.role.downcase =~ role }
162
+ end
163
+
164
+ # Return an array of all roles for parties in this case.
165
+ def roles
166
+ roles = Set.new
167
+ parties.each do |pty|
168
+ roles << pty.role
169
+ end
170
+ roles.to_a
171
+ end
172
+
173
+ # Return a string with the roles of all parties ptys in this kase joined
174
+ # with and.
175
+ def party_roles(ptys)
176
+ # Sort roles by number of parties in each role
177
+ roles = ptys.group_by(&:role).transform_values(&:count).sort
178
+ # Pluralize by count
179
+ role_names = []
180
+ roles.each do |role, count|
181
+ role_names << role.pluralize(count)
182
+ end
183
+ role_names.join_and
184
+ end
185
+
186
+ def tex_lawdoc_caption_inre
187
+ pps = parties_of_role(roles.first)
188
+ body = ''
189
+ unless pps.empty?
190
+ body = '\\textbf{In the Matter of:}\\\\[12pt]'
191
+ pps.each_with_flags do |pty, first, _last|
192
+ body += "\\versusand\n" unless first
193
+ body += "\\aparty{#{pty.name.tq},}\\\\\n"
194
+ end
195
+ body += "\\role{#{roles.first.tq + (pps.size > 1 ? 's' : '')}}"
196
+ end
197
+ # Same body for both styles
198
+ <<~CAPTION
199
+ \\LeftFullCaptionBlock{%\n
200
+ #{body}
201
+ }\n\n
202
+ \\LeftCaptionBlock}{%\n
203
+ #{body}
204
+ }\n\n
205
+ CAPTION
206
+ end
207
+
208
+ # Compute FullLeftCaptionBlock
209
+ def tex_lawdoc_full_caption_versus
210
+ result = "\\LeftFullCaptionBlock{%\n"
211
+ unless plaintiffs.empty?
212
+ pgroups = plaintiffs.group_by(&:role)
213
+ first_group = true
214
+ pgroups.each_value do |ps|
215
+ if first_group
216
+ first_group = false
217
+ else
218
+ result += " \\versusand\n"
219
+ end
220
+ ps.each do |p|
221
+ result += " \\aparty{#{p.name.tq}}\\\\\n"
222
+ end
223
+ role_str = ps.length > 1 ? ps.first.role.pluralize : ps.first.role
224
+ result += " \\role{#{role_str.tq}}\n"
225
+ end
226
+ result += " \\versus\n"
227
+ end
228
+ unless defendants.empty?
229
+ dgroups = defendants.group_by(&:role)
230
+ first_group = true
231
+ dgroups.each_value do |ds|
232
+ if first_group
233
+ first_group = false
234
+ else
235
+ result += " \\versusand\n"
236
+ end
237
+ ds.each do |d|
238
+ result += " \\aparty{#{d.name.tq}}\\\\\n"
239
+ end
240
+ role_str = ds.length > 1 ? ds.first.role.pluralize : ds.first.role
241
+ result += " \\role{#{role_str.tq}}\n"
242
+ end
243
+ end
244
+ unless other_parties.empty?
245
+ ogroups = other_parties.group_by(&:role)
246
+ first_group = true
247
+ ogroups.each_value do |os|
248
+ if first_group
249
+ first_group = false
250
+ else
251
+ result += " \\versusand\n"
252
+ end
253
+ os.each do |d|
254
+ result += " \\aparty{#{d.name.tq}}\\\\\n"
255
+ end
256
+ role_str = os.length > 1 ? os.first.role.pluralize : os.first.role
257
+ result += " \\role{#{role_str.tq}}\n"
258
+ end
259
+ end
260
+ result += "}\n"
261
+ result
262
+ end
263
+
264
+ # Compute LeftCaptionBlock
265
+ def tex_lawdoc_caption_versus
266
+ result = "\\LeftCaptionBlock{%\n"
267
+ unless plaintiffs.empty?
268
+ p = plaintiffs.first
269
+ et_al = plaintiffs.length > 1 ? ', \textit{et al.}' : ''
270
+ role_str = plaintiffs.length > 1 ? p.role.pluralize : p.role
271
+ result += " \\party{#{p.name.tq}#{et_al}}{#{role_str.tq}}\\\\\n"
272
+ result += " \\versus\n"
273
+ end
274
+ unless defendants.empty?
275
+ d = defendants.first
276
+ et_al = defendants.length > 1 ? ', \textit{et al.}' : ''
277
+ role_str = defendants.length > 1 ? d.role.pluralize : d.role
278
+ result += " \\party{#{d.name.tq}#{et_al}}{#{role_str.tq}}\\\\\n"
279
+ end
280
+ result += "}\n"
281
+ result
282
+ end
283
+
284
+ def tex_lawdoc_caption
285
+ if style == :inre
286
+ tex_lawdoc_caption_inre
287
+ else
288
+ tex_lawdoc_caption_versus
289
+ end
290
+ end
291
+
292
+ def tex_lawdoc_full_caption
293
+ if style == :inre
294
+ tex_lawdoc_full_caption_inre
295
+ else
296
+ tex_lawdoc_full_caption_versus
297
+ end
298
+ end
299
+
300
+ def tex_lawdoc_macros
301
+ result = ''
302
+ result += "\\CaseNumber{#{number.tq}}\n"
303
+ if judge
304
+ result += "\\JudgeInitials{#{judge.initials.tq}}\n"
305
+ result += "\\JudgeLast{#{judge.last.tq}}\n"
306
+ result += "\\JudgeName{#{judge.name.tq}}\n"
307
+ end
308
+ if magistrate
309
+ result += "\\MagistrateInitials{#{magistrate.initials.tq}}\n"
310
+ result += "\\MagistrateLast{#{magistrate.last.tq}}\n"
311
+ result += "\\MagistrateName{#{magistrate.name.tq}}\n"
312
+ end
313
+ result += tex_lawdoc_caption
314
+ result += tex_lawdoc_full_caption
315
+ result
316
+ end
317
+ end
318
+ end
@@ -0,0 +1,51 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
3
+ class Array
4
+ def non_blank
5
+ select { |x| !x.blank? }
6
+ end
7
+
8
+ def join_nonblank(sep = ' ')
9
+ non_blank.join(sep)
10
+ end
11
+
12
+ def join_serial(sep = ', ', last_sep = ', ')
13
+ result = ''
14
+ non_blank.each_with_flags do |itm, first, last|
15
+ next if itm.blank?
16
+ result +=
17
+ if first
18
+ itm.to_s
19
+ elsif last
20
+ "#{last_sep}#{itm}"
21
+ else
22
+ "#{sep}#{itm}"
23
+ end
24
+ end
25
+ result
26
+ end
27
+
28
+ def join_and
29
+ items = non_blank
30
+ case items.size
31
+ when 1
32
+ items.first.to_s
33
+ when 2
34
+ items.join(' and ')
35
+ else
36
+ join_serial(', ', ', and ')
37
+ end
38
+ end
39
+
40
+ def join_or
41
+ items = non_blank
42
+ case items.size
43
+ when 1
44
+ items.first.to_s
45
+ when 2
46
+ items.join(' and ')
47
+ else
48
+ join_serial(', ', ', or ')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ class NilClass
2
+ def tex_block
3
+ ''
4
+ end
5
+
6
+ def tq
7
+ ''
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ class Numeric
2
+ def ordinal
3
+ if abs < 10
4
+ # Single digit
5
+ if abs == 1
6
+ "#{self}st"
7
+ elsif self.abs == 2
8
+ "#{self}nd"
9
+ elsif self.abs == 3
10
+ "#{self}rd"
11
+ else
12
+ "#{self}th"
13
+ end
14
+ elsif [0, 4, 5, 6, 7, 8, 9].include?(abs % 10) ||
15
+ [11, 12, 13].include?(abs % 100)
16
+ "#{self}th"
17
+ elsif abs % 10 == 1
18
+ "#{self}st"
19
+ elsif abs % 10 == 2
20
+ "#{self}nd"
21
+ elsif abs % 10 == 3
22
+ "#{self}rd"
23
+ else
24
+ raise "Numeric#ordinal unhandled case: #{self}"
25
+ end
26
+ end
27
+
28
+ def month_name
29
+ index = (abs % 12) - 1
30
+ months = %w[January February March April May June July August
31
+ September October November December ]
32
+ months[index]
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ class String
2
+ alias tq tex_quote
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'law_doc/core_ext/array'
2
+ require 'law_doc/core_ext/numeric'
3
+ require 'law_doc/core_ext/string'
4
+ require 'law_doc/core_ext/nil'
@@ -0,0 +1,48 @@
1
+ module LawDoc
2
+ class Court < Person
3
+ attr_reader :division, :district, :state
4
+
5
+ def initialize(division: nil,
6
+ district: nil,
7
+ state: nil,
8
+ **other)
9
+ other[:sex] = 'entity'
10
+ super(**other)
11
+ @district = district
12
+ @division = division
13
+ @state = state
14
+ end
15
+
16
+ def to_h
17
+ super.merge({ division: division,
18
+ district: district,
19
+ state: state })
20
+ end
21
+
22
+ include Comparable
23
+
24
+ def <=>(other)
25
+ to_h <=> other.to_h
26
+ end
27
+
28
+ def tex_lawdoc_forum
29
+ components = []
30
+ components << '\\begin{center}'
31
+ components << "#{name.tq}\\\\"
32
+ components << "For the #{district.tq}\\\\" if district
33
+ components << "(#{division.tq} Division)\\\\" if division
34
+ components << '\\end{center}'
35
+ components.join_nonblank("\n")
36
+ end
37
+
38
+ def tex_lawdoc_macros
39
+ <<~ENDM
40
+ \\renewcommand{\\Forum}{#{tex_lawdoc_forum}}
41
+ \\renewcommand{\\CourtName}{#{name.tq}}
42
+ \\renewcommand{\\CourtDistrict}{#{district.tq}}
43
+ \\renewcommand{\\CourtDivision}{#{division.tq}}
44
+ \\renewcommand{\\CourtState}{#{state.tq}}
45
+ ENDM
46
+ end
47
+ end
48
+ end