citeproc 1.0.0.pre12 → 1.0.0

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.simplecov +4 -0
  3. data/AGPL +1 -1
  4. data/BSDL +2 -2
  5. data/Gemfile +39 -19
  6. data/README.md +123 -14
  7. data/Rakefile +22 -8
  8. data/cucumber.yml +1 -1
  9. data/features/step_definitions/processor.rb +59 -0
  10. data/features/support/env.rb +45 -2
  11. data/lib/citeproc.rb +8 -8
  12. data/lib/citeproc/abbreviate.rb +5 -4
  13. data/lib/citeproc/assets.rb +109 -109
  14. data/lib/citeproc/attributes.rb +11 -11
  15. data/lib/citeproc/bibliography.rb +107 -71
  16. data/lib/citeproc/citation_data.rb +175 -150
  17. data/lib/citeproc/compatibility.rb +5 -108
  18. data/lib/citeproc/date.rb +23 -12
  19. data/lib/citeproc/engine.rb +9 -4
  20. data/lib/citeproc/errors.rb +6 -6
  21. data/lib/citeproc/extensions.rb +66 -66
  22. data/lib/citeproc/item.rb +60 -2
  23. data/lib/citeproc/names.rb +103 -24
  24. data/lib/citeproc/number.rb +27 -8
  25. data/lib/citeproc/processor.rb +31 -41
  26. data/lib/citeproc/selector.rb +132 -126
  27. data/lib/citeproc/utilities.rb +6 -6
  28. data/lib/citeproc/variable.rb +5 -4
  29. data/lib/citeproc/version.rb +1 -1
  30. data/spec/citeproc/assets_spec.rb +17 -15
  31. data/spec/citeproc/bibliography_spec.rb +17 -17
  32. data/spec/citeproc/citation_data_spec.rb +90 -90
  33. data/spec/citeproc/engine_spec.rb +3 -4
  34. data/spec/citeproc/item_spec.rb +76 -68
  35. data/spec/citeproc/names_spec.rb +187 -148
  36. data/spec/citeproc/processor_spec.rb +119 -115
  37. data/spec/citeproc/selector_spec.rb +87 -78
  38. data/spec/citeproc/variable_spec.rb +30 -30
  39. data/spec/fixtures/locales/locales-en-US.xml +304 -0
  40. data/spec/spec_helper.rb +32 -1
  41. data/tasks/testsuite.rb +209 -0
  42. metadata +19 -87
  43. data/.gitignore +0 -6
  44. data/.travis.yml +0 -21
  45. data/citeproc.gemspec +0 -40
@@ -10,9 +10,9 @@ module CiteProc
10
10
  def abbreviations=(abbreviations)
11
11
  @abbreviations = case abbreviations
12
12
  when ::String
13
- MultiJson.decode(abbreviations, :symbolize_keys => true)
13
+ ::JSON.parse(abbreviations, :symbolize_names => true)
14
14
  when ::Hash
15
- abbreviations.deep_copy
15
+ abbreviations.deep_copy.symbolize_keys
16
16
  else
17
17
  raise ArgumentError, "failed to set abbreviations from #{abbreviations.inspect}"
18
18
  end
@@ -20,11 +20,12 @@ module CiteProc
20
20
 
21
21
  # @overload abbreviate(namespace = :default, context, word)
22
22
  def abbreviate(*arguments)
23
- raise ArgumentError, "wrong number of arguments (#{arguments.length} for 2..3)" unless (2..3).include?(arguments.length)
23
+ raise ArgumentError, "wrong number of arguments (#{arguments.length} for 2..3)" unless
24
+ (2..3).include?(arguments.length)
25
+
24
26
  arguments.unshift(namespace || :default) if arguments.length < 3
25
27
  @abbreviations.deep_fetch(*arguments)
26
28
  end
27
-
28
29
  alias abbrev abbreviate
29
30
 
30
31
  end
@@ -1,113 +1,113 @@
1
1
  module CiteProc
2
2
 
3
- module Asset
4
-
5
- def self.included(base)
6
- base.extend(ClassMethods)
7
- end
8
-
9
- attr_reader :asset, :location
10
-
11
- def open?
12
- !asset.nil?
13
- end
14
-
15
- def open(input)
16
- case
17
- when input.respond_to?(:read)
18
- @location = nil
19
- @asset = input.read
20
- when input.to_s =~ /^\s*</
21
- @location = nil
22
- @asset = input.to_s.dup
23
- else
24
- case
25
- when File.exists?(input)
26
- @location = input
27
- when File.exists?(self.class.extend_name(input))
28
- @location = self.class.extend_name(input)
29
- when File.exists?(self.class.extend_path(input))
30
- @location = self.class.extend_path(input)
31
- else
32
- @location = input
33
- end
34
-
35
- Kernel.open(@location, 'r:UTF-8') do |io|
36
- @asset = io.read
37
- end
38
- end
39
-
40
- self
41
- rescue => e
42
- raise ArgumentError, "failed to open asset #@location (#{input.inspect}): #{e.message}"
43
- end
44
-
45
- def name
46
- File.basename(location, self.class.extension).sub(Regexp.new("^#{self.class.prefix}"), '')
47
- end
48
-
49
- alias to_s asset
50
-
51
- def inspect
52
- "#<CiteProc::#{self.class.name} #{name}>"
53
- end
54
-
55
- module ClassMethods
56
-
57
- attr_accessor :root, :extension, :prefix
58
-
59
- def open(path_or_name)
60
- new.open(path_or_name)
61
- end
62
-
63
- def extend_path(input)
64
- File.join(root.to_s, extend_name(input))
65
- end
66
-
67
- def extend_name(input)
68
- if File.extname(input) != extension
69
- name = [input, extension].compact.join
70
- else
71
- name = input.to_s.dup
72
- end
73
-
74
- unless name.start_with?(prefix.to_s)
75
- name = [prefix, name].join
76
- end
77
-
78
- name
79
- end
80
-
81
- end
82
-
83
- end
84
-
85
- class Style
86
-
87
- include Asset
88
-
89
- @root = '/usr/local/share/citation-style-language/styles'.freeze
90
- @extension = '.csl'.freeze
91
-
92
- end
93
-
94
- class Locale
95
-
96
- include Asset
97
-
98
- @root = '/usr/local/share/citation-style-language/locales'.freeze
99
- @extension = '.xml'.freeze
100
- @prefix = 'locales-'.freeze
101
-
102
-
103
- def language
104
- name.split('-')[0]
105
- end
106
-
107
- def region
108
- name.split('-')[1]
109
- end
110
-
111
- end
3
+ module Asset
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ attr_reader :asset, :location
10
+
11
+ def open?
12
+ !asset.nil?
13
+ end
14
+
15
+ def open(input)
16
+ case
17
+ when input.respond_to?(:read)
18
+ @location = nil
19
+ @asset = input.read
20
+ when input.to_s =~ /^\s*</
21
+ @location = nil
22
+ @asset = input.to_s.dup
23
+ else
24
+ case
25
+ when File.exists?(input)
26
+ @location = input
27
+ when File.exists?(self.class.extend_name(input))
28
+ @location = self.class.extend_name(input)
29
+ when File.exists?(self.class.extend_path(input))
30
+ @location = self.class.extend_path(input)
31
+ else
32
+ @location = input
33
+ end
34
+
35
+ Kernel.open(@location, 'r:UTF-8') do |io|
36
+ @asset = io.read
37
+ end
38
+ end
39
+
40
+ self
41
+ rescue => e
42
+ raise ArgumentError, "failed to open asset #@location (#{input.inspect}): #{e.message}"
43
+ end
44
+
45
+ def name
46
+ File.basename(location, self.class.extension).sub(Regexp.new("^#{self.class.prefix}"), '')
47
+ end
48
+
49
+ alias to_s asset
50
+
51
+ def inspect
52
+ "#<CiteProc::#{self.class.name} #{name}>"
53
+ end
54
+
55
+ module ClassMethods
56
+
57
+ attr_accessor :root, :extension, :prefix
58
+
59
+ def open(path_or_name)
60
+ new.open(path_or_name)
61
+ end
62
+
63
+ def extend_path(input)
64
+ File.join(root.to_s, extend_name(input))
65
+ end
66
+
67
+ def extend_name(input)
68
+ if File.extname(input) != extension
69
+ name = [input, extension].compact.join
70
+ else
71
+ name = input.to_s.dup
72
+ end
73
+
74
+ unless name.start_with?(prefix.to_s)
75
+ name = [prefix, name].join
76
+ end
77
+
78
+ name
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ class Style
86
+
87
+ include Asset
88
+
89
+ @root = '/usr/local/share/citation-style-language/styles'.freeze
90
+ @extension = '.csl'.freeze
91
+
92
+ end
93
+
94
+ class Locale
95
+
96
+ include Asset
97
+
98
+ @root = '/usr/local/share/citation-style-language/locales'.freeze
99
+ @extension = '.xml'.freeze
100
+ @prefix = 'locales-'.freeze
101
+
102
+
103
+ def language
104
+ name.split('-')[0]
105
+ end
106
+
107
+ def region
108
+ name.split('-')[1]
109
+ end
110
+
111
+ end
112
112
 
113
113
  end
@@ -23,16 +23,16 @@ module CiteProc
23
23
  def write_attribute(key, value)
24
24
  attributes[filter_key(key)] = filter_value(value, key)
25
25
  end
26
- alias []= write_attribute
26
+ alias []= write_attribute
27
27
 
28
- def attribute?(key)
29
- value = read_attribute key
28
+ def attribute?(key)
29
+ value = read_attribute key
30
30
 
31
- return false if value.nil?
32
- return false if value.respond_to?(:empty?) && value.empty?
31
+ return false if value.nil?
32
+ return false if value.respond_to?(:empty?) && value.empty?
33
33
 
34
- value.to_s !~ /^(false|no|never)$/i
35
- end
34
+ value.to_s !~ /^(false|no|never)$/i
35
+ end
36
36
 
37
37
  def filter_key(key)
38
38
  key.to_sym
@@ -49,7 +49,7 @@ module CiteProc
49
49
 
50
50
  case
51
51
  when other.is_a?(String) && /^\s*\{/ =~ other
52
- other = MultiJson.decode(other, :symbolize_keys => true)
52
+ other = ::JSON.parse(other, :symbolize_names => true)
53
53
  when other.respond_to?(:each_pair)
54
54
  # do nothing
55
55
  when other.respond_to?(:to_hash)
@@ -83,7 +83,7 @@ module CiteProc
83
83
 
84
84
  # @return [String] a JSON string representation of the attributes
85
85
  def to_json
86
- MultiJson.encode(to_citeproc)
86
+ ::JSON.dump(to_citeproc)
87
87
  end
88
88
 
89
89
  # Don't expose internals to public API
@@ -173,7 +173,7 @@ module CiteProc
173
173
  predicate_id = [method_id, '?'].join
174
174
  if predicate && !instance_methods.include?(predicate_id)
175
175
  define_method(predicate_id) do
176
- attribute?(field)
176
+ attribute?(field)
177
177
  end
178
178
 
179
179
  has_predicate = ['has_', predicate_id].join
@@ -184,4 +184,4 @@ module CiteProc
184
184
  end
185
185
 
186
186
  end
187
- end
187
+ end
@@ -13,30 +13,30 @@ module CiteProc
13
13
 
14
14
  @defaults = {
15
15
  :offset => 0,
16
- :entry_spacing => 0,
17
- :line_spacing => 0,
18
- :indent => 0,
19
- :align => false
16
+ :'entry-spacing' => 1,
17
+ :'line-spacing' => 1,
18
+ :'hanging-indent' => false,
19
+ :'second-field-align' => false
20
20
  }.freeze
21
-
22
-
21
+
22
+
23
23
  # citeproc-js and csl attributes are often inconsistent or difficult
24
24
  # to use as symbols/method names, so we're using different names at the
25
25
  # cost of making conversion to and from the json format more difficult
26
-
26
+
27
27
  @cp2rb = {
28
28
  'maxoffset' => :offset,
29
- 'entryspacing' => :entry_spacing,
30
- 'linespacing' => :line_spacing,
31
- 'hangingindent' => :indent,
32
- 'second-field-align' => :align
29
+ 'entryspacing' => :'entry-spacing',
30
+ 'linespacing' => :'line-spacing',
31
+ 'hangingindent' => :'hanging-indent',
32
+ 'second-field-align' => :'second-field-align'
33
33
  }
34
-
34
+
35
35
  @rb2cp = @cp2rb.invert.freeze
36
36
  @cp2rb.freeze
37
-
37
+
38
38
  class << self
39
-
39
+
40
40
  # @!attribute [r] defaults
41
41
  # @example Default Formatting Options
42
42
  # {
@@ -54,19 +54,17 @@ module CiteProc
54
54
  # # string should use this value to calculate and apply a suitable
55
55
  # # indentation length.
56
56
  #
57
- # :entry_spacing => 0,
57
+ # :'entry-spacing' => 1,
58
58
  # # An integer representing the spacing between entries in the
59
59
  # # bibliography.
60
60
  #
61
- # :line_spacing => 0,
61
+ # :'line-spacing' => 1,
62
62
  # # An integer representing the spacing between the lines within
63
63
  # # each bibliography entry.
64
64
  #
65
- # :indent => 0,
66
- # # The number of em-spaces to apply in hanging indents within the
67
- # # bibliography.
65
+ # :'hanging-indent' => false,
68
66
  #
69
- # :align => false
67
+ # :'second-field-align' => false
70
68
  # # When the second-field-align CSL option is set, this returns
71
69
  # # either "flush" or "margin". The calling application should
72
70
  # # align text in the bibliography output as described by the CSL
@@ -77,105 +75,143 @@ module CiteProc
77
75
  attr_reader :defaults
78
76
 
79
77
  attr_reader :cp2rb, :rb2cp
80
-
78
+
81
79
  # Create a new Bibliography from the passed-in string or array, or nil
82
80
  # if the input cannot be parsed.
83
- def create(input)
84
- create!(input)
81
+ def create(input, &block)
82
+ create!(input, &block)
85
83
  rescue
86
84
  nil
87
85
  end
88
-
86
+
89
87
  # Create a new Bibliography from the passed-in string or array. Raises
90
88
  # ParseError if the input cannot be parsed.
91
89
  def create!(input)
92
90
  case
93
91
  when input.is_a?(String)
94
- create!(MultiJson.decode(input))
95
-
92
+ create!(::JSON.parse(input))
93
+
94
+ when input.is_a?(Hash)
95
+ create!([input])
96
+
96
97
  when input.is_a?(Array) && input.length == 2
97
98
  options, references = input
98
99
 
99
100
  new do |b|
100
- b.concat(references)
101
+ b.references.concat(references)
102
+ b.ids.concat(options.fetch('entry_ids', []))
101
103
  b.errors.concat(options.fetch('bibliography_errors', []))
102
-
103
- b.prefix, b.suffix = options['bibstart'], options['bibend']
104
-
104
+
105
+ b.header, b.footer = options['bibstart'], options['bibend']
106
+
105
107
  (options.keys & cp2rb.keys).each do |k|
106
108
  b.options[cp2rb[k]] = options[k]
107
109
  end
110
+
111
+ yield b if block_given?
108
112
  end
109
-
113
+
110
114
  else
111
115
  raise ParseError, "failed to create Bibliography from #{input.inspect}"
112
116
  end
113
117
  end
114
-
118
+
115
119
  end
116
-
120
+
117
121
  include Comparable
118
122
  include Enumerable
119
-
123
+
120
124
  extend Forwardable
121
125
 
122
126
  # @!attribute [r] refrences
123
127
  # @return [Array<String>] the list of references
124
128
  attr_reader :references
125
-
129
+
130
+ attr_reader :ids
131
+
126
132
  # @!attribute [r] options
127
133
  # @see .defaults
128
134
  # @return [Hash] the current formatting options
129
135
  attr_reader :options
130
-
136
+
131
137
  # @!attribute [r] errors
132
- # @todo not implemented yet
133
138
  # @return [Array<String>] a list of errors
134
139
  attr_reader :errors
135
140
 
136
- # @!attribute prefix
141
+ # @!attribute header
137
142
  # @return [String] content included before the reference list
138
- attr_accessor :prefix, :suffix
143
+ attr_accessor :header
139
144
 
140
- # @!attribute suffix
145
+ # @!attribute footer
141
146
  # @return [String] content included after the reference list
142
- attr_accessor :suffix
147
+ attr_accessor :footer
143
148
 
149
+ # @!attribute prefix
150
+ # @return [String] content included before each reference
151
+ attr_accessor :prefix
152
+
153
+ # @!attribute suffix
154
+ # @return [String] content included after each reference
155
+ attr_accessor :suffix
144
156
 
145
157
  # Bibliographies quack sorta like an Array
146
- def_delegators :@references, :length, :empty?, :[], :include?, :index
158
+ def_delegators :@references, :length, :empty?
159
+
160
+ attr_accessor :connector
147
161
 
148
- # Some delegators should return self
149
- [:push, :<<, :unshift, :concat].each do |m|
150
- define_method(m) do |*arguments, &block|
151
- references.send(m, *arguments, &block)
152
- self
153
- end
154
- end
155
-
156
-
157
162
  def initialize(options = {})
158
163
  @options = Bibliography.defaults.merge(options)
159
- @errors, @references = [], []
160
-
164
+ @errors, @references, @ids, @connector = [], [], [], "\n"
165
+
161
166
  yield self if block_given?
162
167
  end
163
-
168
+
164
169
  def initialize_copy(other)
165
- @options = other.options.dup
166
- @errors, @references = other.errors.dup, other.references.dup
170
+ @options, @connector = other.options.dup, other.connector.dup
171
+ @errors, @references, @ids = other.errors.dup, other.references.dup, other.ids.dup
172
+ end
173
+
174
+ def push(id, reference)
175
+ ids << id
176
+ references << reference
177
+ self
167
178
  end
179
+ alias << push
168
180
 
169
181
  def has_errors?
170
182
  !errors.empty?
171
183
  end
172
-
184
+
173
185
  alias errors? has_errors?
174
-
175
- def join(connector = "\n")
176
- [prefix, references.join(connector), suffix].compact.join
186
+
187
+ def entry_spacing
188
+ options[:'entry-spacing'].to_f
189
+ end
190
+
191
+ def line_spacing
192
+ options[:'line-spacing'].to_f
177
193
  end
178
-
194
+
195
+ def hanging_indent?
196
+ options[:'hanging_indent']
197
+ end
198
+
199
+ def join()
200
+ [
201
+ header,
202
+
203
+ references.map { |r|
204
+ [prefix, r, suffix].compact.join('')
205
+ }.join(connector),
206
+
207
+ footer
208
+ ].compact.join(connector)
209
+ end
210
+
211
+ def to_s
212
+ join
213
+ end
214
+
179
215
  def each
180
216
  if block_given?
181
217
  references.each(&Proc.new)
@@ -184,7 +220,7 @@ module CiteProc
184
220
  to_enum
185
221
  end
186
222
  end
187
-
223
+
188
224
  def <=>(other)
189
225
  return nil unless other.respond_to?(:references)
190
226
  references <=> other.references
@@ -195,29 +231,29 @@ module CiteProc
195
231
  [Bibliography.rb2cp[k] || k.to_s, v]
196
232
  }.flatten]
197
233
  end
198
-
234
+
199
235
  def to_citeproc
200
236
  [
201
- citeproc_options.merge({
237
+ citeproc_options.merge({
202
238
  'bibstart' => prefix,
203
239
  'bibend' => suffix,
204
240
  'bibliography_errors' => errors
205
241
  }),
206
-
242
+
207
243
  references
208
-
244
+
209
245
  ]
210
246
  end
211
-
247
+
212
248
  def to_json
213
- MultiJson.encode(to_citeproc)
249
+ ::JSON.dump(to_citeproc)
214
250
  end
215
-
251
+
216
252
  # @return [String] a human-readable representation of the bibliography
217
253
  def inspect
218
254
  "#<CiteProc::Bibliography @references=[#{references.length}], @errors=[#{errors.length}]>"
219
255
  end
220
-
256
+
221
257
  end
222
-
258
+
223
259
  end