citeproc-ruby 0.0.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.document +4 -0
  4. data/.gitignore +10 -0
  5. data/.rspec +3 -0
  6. data/.simplecov +4 -0
  7. data/.travis.yml +17 -0
  8. data/.yardopts +2 -0
  9. data/AGPL +662 -0
  10. data/BSDL +29 -0
  11. data/Gemfile +42 -0
  12. data/Guardfile +14 -0
  13. data/README.md +32 -76
  14. data/Rakefile +60 -0
  15. data/citeproc-ruby.gemspec +46 -0
  16. data/cucumber.yml +1 -0
  17. data/features/bibliography.feature +25 -0
  18. data/features/name_options.feature +37 -0
  19. data/features/names.feature +192 -0
  20. data/features/renderer.feature +74 -0
  21. data/features/sort.feature +50 -0
  22. data/features/step_definitions/renderer.rb +80 -0
  23. data/features/support/env.rb +33 -0
  24. data/features/support/hooks.rb +10 -0
  25. data/lib/citeproc/ruby.rb +32 -0
  26. data/lib/citeproc/ruby/engine.rb +122 -0
  27. data/lib/citeproc/ruby/format.rb +303 -0
  28. data/lib/citeproc/ruby/formats/default.rb +25 -0
  29. data/lib/citeproc/ruby/formats/html.rb +221 -0
  30. data/lib/citeproc/ruby/renderer.rb +140 -0
  31. data/lib/citeproc/ruby/renderer/choose.rb +106 -0
  32. data/lib/citeproc/ruby/renderer/date.rb +90 -0
  33. data/lib/citeproc/ruby/renderer/format.rb +129 -0
  34. data/lib/citeproc/ruby/renderer/group.rb +34 -0
  35. data/lib/citeproc/ruby/renderer/history.rb +40 -0
  36. data/lib/citeproc/ruby/renderer/label.rb +66 -0
  37. data/lib/citeproc/ruby/renderer/layout.rb +20 -0
  38. data/lib/citeproc/ruby/renderer/locale.rb +26 -0
  39. data/lib/citeproc/ruby/renderer/macro.rb +20 -0
  40. data/lib/citeproc/ruby/renderer/names.rb +401 -0
  41. data/lib/citeproc/ruby/renderer/number.rb +41 -0
  42. data/lib/citeproc/ruby/renderer/observer.rb +44 -0
  43. data/lib/citeproc/ruby/renderer/state.rb +96 -0
  44. data/lib/citeproc/ruby/renderer/text.rb +62 -0
  45. data/lib/citeproc/ruby/sort.rb +82 -0
  46. data/lib/citeproc/ruby/version.rb +5 -0
  47. data/spec/citeproc/ruby/engine_spec.rb +94 -0
  48. data/spec/citeproc/ruby/formats/default_spec.rb +159 -0
  49. data/spec/citeproc/ruby/formats/html_spec.rb +162 -0
  50. data/spec/citeproc/ruby/renderer/choose_spec.rb +293 -0
  51. data/spec/citeproc/ruby/renderer/date_spec.rb +173 -0
  52. data/spec/citeproc/ruby/renderer/group_spec.rb +88 -0
  53. data/spec/citeproc/ruby/renderer/history_spec.rb +38 -0
  54. data/spec/citeproc/ruby/renderer/label_spec.rb +225 -0
  55. data/spec/citeproc/ruby/renderer/layout_spec.rb +41 -0
  56. data/spec/citeproc/ruby/renderer/macro_spec.rb +31 -0
  57. data/spec/citeproc/ruby/renderer/names_spec.rb +396 -0
  58. data/spec/citeproc/ruby/renderer/number_spec.rb +120 -0
  59. data/spec/citeproc/ruby/renderer/text_spec.rb +120 -0
  60. data/spec/citeproc/ruby/renderer_spec.rb +65 -0
  61. data/spec/fixtures/items.rb +80 -0
  62. data/{resource/locale → spec/fixtures/locales}/locales-en-US.xml +2 -11
  63. data/{resource/locale → spec/fixtures/locales}/locales-fr-FR.xml +77 -66
  64. data/{resource/style → spec/fixtures/styles}/apa.csl +5 -5
  65. data/spec/spec_helper.rb +67 -14
  66. metadata +121 -211
  67. data/lib/citeproc.rb +0 -100
  68. data/lib/citeproc/bibliography.rb +0 -57
  69. data/lib/citeproc/data.rb +0 -149
  70. data/lib/citeproc/date.rb +0 -133
  71. data/lib/citeproc/formatter.rb +0 -38
  72. data/lib/citeproc/item.rb +0 -53
  73. data/lib/citeproc/name.rb +0 -284
  74. data/lib/citeproc/processor.rb +0 -166
  75. data/lib/citeproc/selector.rb +0 -61
  76. data/lib/citeproc/variable.rb +0 -82
  77. data/lib/citeproc/version.rb +0 -3
  78. data/lib/csl/locale.rb +0 -223
  79. data/lib/csl/node.rb +0 -72
  80. data/lib/csl/nodes.rb +0 -1418
  81. data/lib/csl/renderer.rb +0 -88
  82. data/lib/csl/sort.rb +0 -61
  83. data/lib/csl/style.rb +0 -110
  84. data/lib/csl/term.rb +0 -124
  85. data/lib/extensions/core.rb +0 -43
  86. data/lib/plugins/filters/bibtex.rb +0 -12
  87. data/lib/plugins/formats/default.rb +0 -134
  88. data/lib/plugins/formats/html.rb +0 -67
  89. data/lib/support/attributes.rb +0 -99
  90. data/lib/support/compatibility.rb +0 -83
  91. data/lib/support/tree.rb +0 -80
  92. data/resource/locale/locales-af-ZA.xml +0 -305
  93. data/resource/locale/locales-ar-AR.xml +0 -306
  94. data/resource/locale/locales-bg-BG.xml +0 -305
  95. data/resource/locale/locales-ca-AD.xml +0 -305
  96. data/resource/locale/locales-cs-CZ.xml +0 -305
  97. data/resource/locale/locales-da-DK.xml +0 -305
  98. data/resource/locale/locales-de-AT.xml +0 -304
  99. data/resource/locale/locales-de-CH.xml +0 -304
  100. data/resource/locale/locales-de-DE.xml +0 -332
  101. data/resource/locale/locales-el-GR.xml +0 -305
  102. data/resource/locale/locales-en-GB.xml +0 -304
  103. data/resource/locale/locales-es-ES.xml +0 -305
  104. data/resource/locale/locales-et-EE.xml +0 -304
  105. data/resource/locale/locales-eu.xml +0 -305
  106. data/resource/locale/locales-fa-IR.xml +0 -304
  107. data/resource/locale/locales-fi-FI.xml +0 -304
  108. data/resource/locale/locales-fr-CA.xml +0 -306
  109. data/resource/locale/locales-he-IL.xml +0 -304
  110. data/resource/locale/locales-hu-HU.xml +0 -305
  111. data/resource/locale/locales-is-IS.xml +0 -304
  112. data/resource/locale/locales-it-IT.xml +0 -305
  113. data/resource/locale/locales-ja-JP.xml +0 -305
  114. data/resource/locale/locales-kh-KH.xml +0 -303
  115. data/resource/locale/locales-km-KH.xml +0 -304
  116. data/resource/locale/locales-ko-KR.xml +0 -305
  117. data/resource/locale/locales-mn-MN.xml +0 -306
  118. data/resource/locale/locales-nb-NO.xml +0 -304
  119. data/resource/locale/locales-nl-NL.xml +0 -304
  120. data/resource/locale/locales-nn-NO.xml +0 -304
  121. data/resource/locale/locales-pl-PL.xml +0 -305
  122. data/resource/locale/locales-pt-BR.xml +0 -304
  123. data/resource/locale/locales-pt-PT.xml +0 -305
  124. data/resource/locale/locales-ro-RO.xml +0 -305
  125. data/resource/locale/locales-ru-RU.xml +0 -306
  126. data/resource/locale/locales-sk-SK.xml +0 -304
  127. data/resource/locale/locales-sl-SI.xml +0 -305
  128. data/resource/locale/locales-sr-RS.xml +0 -305
  129. data/resource/locale/locales-sv-SE.xml +0 -305
  130. data/resource/locale/locales-th-TH.xml +0 -304
  131. data/resource/locale/locales-tr-TR.xml +0 -305
  132. data/resource/locale/locales-uk-UA.xml +0 -306
  133. data/resource/locale/locales-vi-VN.xml +0 -305
  134. data/resource/locale/locales-zh-CN.xml +0 -304
  135. data/resource/locale/locales-zh-TW.xml +0 -305
  136. data/resource/schema/csl-categories.rnc +0 -39
  137. data/resource/schema/csl-data.rnc +0 -98
  138. data/resource/schema/csl-terms.rnc +0 -106
  139. data/resource/schema/csl-types.rnc +0 -39
  140. data/resource/schema/csl-variables.rnc +0 -182
  141. data/resource/schema/csl.rnc +0 -941
  142. data/resource/style/bibtex.csl +0 -177
  143. data/resource/style/chicago-annotated-bibliography.csl +0 -513
  144. data/resource/style/chicago-author-date-basque.csl +0 -707
  145. data/resource/style/chicago-author-date-de.csl +0 -394
  146. data/resource/style/chicago-author-date-listing.csl +0 -434
  147. data/resource/style/chicago-author-date.csl +0 -425
  148. data/resource/style/chicago-dated-note-biblio-no-ibid.csl +0 -472
  149. data/resource/style/chicago-fullnote-bibliography-bb.csl +0 -928
  150. data/resource/style/chicago-fullnote-bibliography-delimiter-fixes.csl +0 -972
  151. data/resource/style/chicago-fullnote-bibliography-no-ibid-delimiter-fixes.csl +0 -963
  152. data/resource/style/chicago-fullnote-bibliography-no-ibid.csl +0 -785
  153. data/resource/style/chicago-fullnote-bibliography.csl +0 -803
  154. data/resource/style/chicago-library-list.csl +0 -511
  155. data/resource/style/chicago-note-biblio-no-ibid.csl +0 -514
  156. data/resource/style/chicago-note-bibliography.csl +0 -530
  157. data/resource/style/chicago-note.csl +0 -388
  158. data/resource/style/chicago-quick-copy.csl +0 -685
  159. data/resource/style/ieee.csl +0 -299
  160. data/resource/style/mla-notes.csl +0 -796
  161. data/resource/style/mla-underline.csl +0 -175
  162. data/resource/style/mla-url.csl +0 -214
  163. data/resource/style/mla.csl +0 -394
  164. data/resource/style/vancouver-brackets.csl +0 -256
  165. data/resource/style/vancouver-superscript-bracket-only-year.csl +0 -165
  166. data/resource/style/vancouver-superscript.csl +0 -256
  167. data/resource/style/vancouver.csl +0 -256
  168. data/spec/citeproc/bibliography_spec.rb +0 -45
  169. data/spec/citeproc/citeproc_spec.rb +0 -80
  170. data/spec/citeproc/date_spec.rb +0 -89
  171. data/spec/citeproc/formatter_spec.rb +0 -101
  172. data/spec/citeproc/item_spec.rb +0 -71
  173. data/spec/citeproc/name_spec.rb +0 -30
  174. data/spec/citeproc/processor_spec.rb +0 -61
  175. data/spec/citeproc/selector_spec.rb +0 -82
  176. data/spec/citeproc/variable_spec.rb +0 -69
  177. data/spec/csl/locale_spec.rb +0 -208
  178. data/spec/csl/node_spec.rb +0 -25
  179. data/spec/csl/nodes_spec.rb +0 -145
  180. data/spec/csl/style_spec.rb +0 -62
  181. data/spec/csl/term_spec.rb +0 -56
  182. data/spec/fixtures/dates.yaml +0 -80
  183. data/spec/fixtures/names.yaml +0 -115
  184. data/spec/fixtures/nodes.yaml +0 -245
  185. data/spec/support/attributes_spec.rb +0 -39
  186. data/spec/support/tree_spec.rb +0 -163
@@ -0,0 +1,25 @@
1
+ module CiteProc
2
+ module Ruby
3
+ module Formats
4
+
5
+ class Text < Format
6
+
7
+ private
8
+
9
+ def finalize!
10
+ super
11
+ output.gsub!(/&(amp|lt|gt);/i, {
12
+ '&amp;' => '&',
13
+ '&gt;' => '>',
14
+ '&lt;' => '<'
15
+ })
16
+ end
17
+
18
+ end
19
+
20
+ class Debug < Format
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,221 @@
1
+ module CiteProc
2
+ module Ruby
3
+ module Formats
4
+
5
+ class Html < Format
6
+
7
+ @defaults = {
8
+ :css_only => false,
9
+ :italic => 'i', # em
10
+ :bold => 'b', # strong
11
+ :container => 'span', # inner container
12
+ :display => 'div', # display container
13
+
14
+ :bib_container => 'ol',
15
+ :bib_container_class => 'csl-bibliography',
16
+ :bib_entry => 'li',
17
+ :bib_entry_class => 'csl-entry',
18
+ :bib_hanging_indent => '0.5',
19
+ :bib_unit => 'em',
20
+ :bib_indent => ' '
21
+ }
22
+
23
+ class << self
24
+ attr_reader :defaults
25
+ end
26
+
27
+ attr_reader :config
28
+
29
+ def initialize(config = nil)
30
+ if config.nil?
31
+ @config = Html.defaults.dup
32
+ else
33
+ @config = Html.defaults.merge(config)
34
+ end
35
+ end
36
+
37
+ def bibliography(bibliography)
38
+ ol, li, indent, unit =
39
+ config.values_at(:bib_container, :bib_entry, :bib_indent, :bib_unit)
40
+
41
+ container_options = {}
42
+ container_options['class'] = config[:bib_container_class]
43
+
44
+ entry_options = {}
45
+ entry_options['class'] = config[:bib_entry_class]
46
+
47
+ entry_options['style'] = {}
48
+ container_options['style'] = {}
49
+
50
+ if bibliography.line_spacing != 1.0
51
+ container_options['style']['line-height'] = bibliography.line_spacing
52
+ end
53
+
54
+ if bibliography.hanging_indent?
55
+ hanging_indent = "#{config[:bib_hanging_indent]}#{bib_unit}"
56
+
57
+ container_options['style']['padding-left'] = hanging_indent
58
+ entry_options['style']['text-indent'] = "-#{hanging_indent}"
59
+ end
60
+
61
+ if bibliography.entry_spacing != 1.0
62
+ entry_options['style']['margin-bottom'] = "#{bibliography.entry_spacing}#{unit}"
63
+ end
64
+
65
+ bibliography.header = opening_tag(ol, container_options)
66
+ bibliography.footer = closing_tag(ol)
67
+
68
+ bibliography.prefix = [indent, opening_tag(li, entry_options)].join('')
69
+ bibliography.suffix = closing_tag(li)
70
+
71
+ bibliography.connector = indent ? "\n" : ''
72
+ bibliography
73
+ end
74
+
75
+ def css_only?
76
+ config[:css_only]
77
+ end
78
+
79
+ def apply_font_style
80
+ if options[:'font-style'] == 'italic' && !css_only?
81
+ output.replace content_tag(config[:italic], output)
82
+ else
83
+ css['font-style'] = options[:'font-style']
84
+ end
85
+ end
86
+
87
+ def apply_font_variant
88
+ css['font-variant'] = options[:'font-variant']
89
+ end
90
+
91
+ def apply_font_weight
92
+ if options[:'font-weight'] == 'bold' && !css_only?
93
+ output.replace content_tag(config[:bold], output)
94
+ else
95
+ css['font-weight'] = options[:'font-weight']
96
+ end
97
+ end
98
+
99
+ def apply_text_decoration
100
+ css['text-decoration'] = options[:'text-decoration']
101
+ end
102
+
103
+ def apply_vertical_align
104
+ css['vertical-align'] = options[:'vertical-align']
105
+ end
106
+
107
+ def apply_display
108
+ output.replace(
109
+ content_tag(config[:display], output, 'class' => "csl-#{options[:display]}" )
110
+ )
111
+ end
112
+
113
+ def prefix
114
+ CSL.encode_xml_text(options[:prefix])
115
+ end
116
+
117
+ def suffix
118
+ CSL.encode_xml_text(options[:suffix])
119
+ end
120
+
121
+ def escape_quotes?
122
+ true
123
+ end
124
+
125
+ def strip(string)
126
+ string.split(/((?:^<[^>]+>)|(?:<[^>]+>))$/, 2)
127
+ end
128
+
129
+ protected
130
+
131
+ def css
132
+ @css ||= {}
133
+ end
134
+
135
+ def finalize_content!
136
+ super
137
+ output.replace content_tag(config[:container], output, 'style' => css) if @css
138
+ end
139
+
140
+ def setup!
141
+ # TODO find a better solution for this (strip tags?)
142
+ # For now make sure not to double encode entities
143
+ # by matching spaces before or after.
144
+
145
+ output.gsub!(/[&<]\s/, '& ' => '&amp; ', '< ' => '&lt; ')
146
+ output.gsub!(/\s>/, ' &gt;')
147
+ end
148
+
149
+ def cleanup!
150
+ @css = nil
151
+ super
152
+ end
153
+
154
+ private
155
+
156
+ def content_tag(name, content, options = nil)
157
+ opening_tag(name, options) << content << closing_tag(name)
158
+ end
159
+
160
+ def style_for(options)
161
+ return unless options && !options.empty?
162
+ options.map { |*kv| kv.join(': ') }.join('; ')
163
+ end
164
+
165
+ def attribute_assignments(options)
166
+ return unless options
167
+
168
+ options = options.select { |k, v| !v.nil? }
169
+
170
+ return unless !options.empty?
171
+
172
+ ' ' << options.map { |k, v| [k, v.inspect].join('=') }.join(' ')
173
+ end
174
+
175
+ def opening_tag(name, options = nil)
176
+ if options && options.key?('style')
177
+ options['style'] = style_for(options['style'])
178
+ end
179
+
180
+ "<#{name}#{attribute_assignments(options)}>"
181
+ end
182
+
183
+ def closing_tag(name)
184
+ "</#{name}>"
185
+ end
186
+ end
187
+
188
+ class CiteProcJS < Html
189
+ def initialize
190
+ super(
191
+ :bib_container => 'div',
192
+ :bib_container_class => 'csl-bib-body',
193
+ :bib_entry => 'div',
194
+ :bib_entry_class => 'csl-entry'
195
+ )
196
+ end
197
+
198
+ def bibliography(bibliography)
199
+ ol, li, indent =
200
+ config.values_at(:bib_container, :bib_entry, :bib_indent)
201
+
202
+ container_options = {}
203
+ container_options['class'] = config[:bib_container_class]
204
+
205
+ entry_options = {}
206
+ entry_options['class'] = config[:bib_entry_class]
207
+
208
+ bibliography.header = opening_tag(ol, container_options)
209
+ bibliography.footer = closing_tag(ol)
210
+
211
+ bibliography.prefix = [indent, opening_tag(li, entry_options)].join('')
212
+ bibliography.suffix = closing_tag(li)
213
+
214
+ bibliography.connector = indent ? "\n" : ''
215
+ bibliography
216
+ end
217
+ end
218
+
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,140 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ class Renderer
5
+
6
+ attr_reader :state
7
+
8
+ attr_accessor :engine
9
+
10
+ def initialize(options_or_engine = nil)
11
+ @state = State.new
12
+
13
+ case options_or_engine
14
+ when Engine
15
+ @engine = options_or_engine
16
+ when Hash
17
+ locale, format = options_or_engine.values_at(:locale, :format)
18
+ @locale, @format = CSL::Locale.load(locale), Format.load(format)
19
+ end
20
+ end
21
+
22
+ def locale
23
+ @locale ||= CSL::Locale.load
24
+ end
25
+
26
+ def locale=(new_locale)
27
+ @locale = CSL::Locale.load new_locale
28
+ end
29
+
30
+ def abbreviate(*arguments)
31
+ return unless engine
32
+ engine.abbreviate(*arguments)
33
+ end
34
+ alias abbrev abbreviate
35
+
36
+ def allow_locale_overrides?
37
+ return false unless engine
38
+ engine.options[:allow_locale_overrides]
39
+ end
40
+
41
+ # @param item [CiteProc::CitationItem]
42
+ # @param node [CSL::Node]
43
+ # @return [String] the rendered and formatted string
44
+ def render(item, node)
45
+ raise ArgumentError, "no CSL node: #{node.inspect}" unless
46
+ node.respond_to?(:nodename)
47
+
48
+ specialize = "render_#{node.nodename.tr('-', '_')}"
49
+
50
+ raise ArgumentError, "#{specialize} not implemented" unless
51
+ respond_to?(specialize, true)
52
+
53
+ format! send(specialize, item, node), node
54
+ end
55
+
56
+ # @param data [CiteProc::CitationData]
57
+ # @param node [CSL::Style::Citation]
58
+ # @return [String] the rendered and formatted string
59
+ def render_citation(data, node)
60
+ state.store! data, node
61
+
62
+ citations = join data.map { |item|
63
+ render_single_citation item, node.layout
64
+ }, node.layout.delimiter || ''
65
+
66
+ result = format! citations, node.layout
67
+ ensure
68
+ state.clear! result
69
+ end
70
+
71
+ # @param data [CiteProc::CitationItem]
72
+ # @param node [CSL::Style::Layout]
73
+ # @return [String] the rendered and string
74
+ def render_single_citation(item, node)
75
+ # TODO author_only
76
+ item.suppress! 'author' if item.suppress_author?
77
+
78
+ join [item.prefix, render_layout(item, node), item.suffix].compact
79
+ end
80
+
81
+ # @param item [CiteProc::CitationItem]
82
+ # @param node [CSL::Style::Bibliography]
83
+ # @return [String] the rendered and formatted string
84
+ def render_bibliography(item, node)
85
+ state.store! item, node
86
+
87
+ if allow_locale_overrides? && item.language != locale.language
88
+ begin
89
+ new_locale = CSL::Locale.load(item.language)
90
+
91
+ unless new_locale.nil?
92
+ new_locale.merge!(locale)
93
+ original_locale, @locale = @locale, new_locale
94
+ end
95
+ rescue ParseError
96
+ # locale not found
97
+ end
98
+ end
99
+
100
+ result = render item, node.layout
101
+
102
+ ensure
103
+ unless original_locale.nil?
104
+ @locale = original_locale
105
+ end
106
+
107
+ state.clear! result
108
+ end
109
+
110
+ def render_sort(a, b, node, key)
111
+ state.store! nil, key
112
+
113
+ original_format = @format
114
+ @format = Formats::Text.new
115
+
116
+ if a.is_a?(CiteProc::Names)
117
+ [render_name(a, node), render_name(b, node)]
118
+
119
+ else
120
+ # We need to clear any items that are suppressed
121
+ # because they were used as substitutes during
122
+ # rendering for sorting purposes!
123
+ a_rendered = render a.cite, node
124
+ a.suppressed.clear
125
+
126
+ b_rendered = render b.cite, node
127
+ b.suppressed.clear
128
+
129
+ [a_rendered, b_rendered]
130
+ end
131
+
132
+ ensure
133
+ @format = original_format
134
+ state.clear!
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,106 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ class Renderer
5
+
6
+ # @param item [CiteProc::CitationItem]
7
+ # @param node [CSL::Style::Choose]
8
+ # @return [String]
9
+ def render_choose(item, node)
10
+ return '' unless node.has_children?
11
+
12
+ node.each_child do |child|
13
+ return render_block(item, child) if evaluates?(item, child)
14
+ end
15
+
16
+ '' # no block was rendered
17
+ end
18
+
19
+ # @param item [CiteProc::CitationItem]
20
+ # @param node [CSL::Style::Choose::Block]
21
+ # @return [String]
22
+ def render_block(item, node)
23
+ return '' unless node.has_children?
24
+
25
+ join node.each_child.map { |child|
26
+ render item, child
27
+ }
28
+ end
29
+
30
+
31
+ # Evaluates the conditions of the passed-in Choose::Block
32
+ # against the passed-in CitationItem using the Block's matcher.
33
+ #
34
+ # @param item [CiteProc::CitationItem]
35
+ # @param node [CSL::Style::Choose::Block]
36
+ #
37
+ # @return [Boolean] whether or not the node's conditions
38
+ # are true for the passed-in item
39
+ def evaluates?(item, node)
40
+
41
+ # subtle: else-nodes have no conditions. since the default
42
+ # matcher :all? returns true for an empty list we do not
43
+ # need to check for an else node specifically.
44
+
45
+ # return true if node.nodename == 'else'
46
+
47
+ node.conditions.send(node.matcher) do |type, matcher, values|
48
+ case type
49
+ when :disambiguate
50
+ false # TODO not implemented yet
51
+
52
+ when :'is-numeric'
53
+ evaluates_condition? matcher, values do |value|
54
+ v = item.data.unobservable_read_attribute(value)
55
+ v.respond_to?(:numeric?) && v.numeric?
56
+ end
57
+
58
+ when :'is-uncertain-date'
59
+ evaluates_condition? matcher, values do |value|
60
+ v = item.data.unobservable_read_attribute(value)
61
+ v.respond_to?(:uncertain?) && v.uncertain?
62
+ end
63
+
64
+
65
+ when :locator
66
+ locator = item.locator.to_s.tr(' ', '-')
67
+
68
+ evaluates_condition? matcher, values do |value|
69
+ value.to_s == locator
70
+ end
71
+
72
+ when :position
73
+ false # TODO not implemented yet
74
+
75
+ when :type
76
+ type = item.data.unobservable_read_attribute(:type).to_s
77
+
78
+ evaluates_condition? matcher, values do |value|
79
+ value.to_s == type
80
+ end
81
+
82
+ when :variable
83
+ evaluates_condition? matcher, values do |value|
84
+ item.data.attribute?(value)
85
+ end
86
+
87
+ else
88
+ fail "unknown condition type: #{type}"
89
+ end
90
+ end
91
+ end
92
+
93
+ # Evaluates the passed-in block for each value in values,
94
+ # negating the result if the value is prefixed with 'not:'
95
+ def evaluates_condition?(matcher, values, &condition)
96
+ values.send(matcher) do |value|
97
+ value, negate = value.split(/^not:/, 2).reverse
98
+ result = condition.call(value)
99
+
100
+ negate ? !result : result
101
+ end
102
+ end
103
+ end
104
+
105
+ end
106
+ end