citeproc 1.0.0.pre12 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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