citeproc 0.0.1 → 0.0.2
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.
- data/Gemfile +9 -0
- data/auto.watchr +1 -1
- data/lib/citeproc.rb +12 -1
- data/lib/citeproc/attributes.rb +95 -0
- data/lib/citeproc/compatibility.rb +10 -0
- data/lib/citeproc/date.rb +166 -0
- data/lib/citeproc/engine.rb +17 -5
- data/lib/citeproc/errors.rb +4 -4
- data/lib/citeproc/extensions.rb +16 -1
- data/lib/citeproc/processor.rb +7 -2
- data/lib/citeproc/variable.rb +121 -0
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/abbreviate_spec.rb +1 -1
- data/spec/citeproc/attributes_spec.rb +40 -0
- data/spec/citeproc/date_spec.rb +103 -0
- data/spec/citeproc/engine_spec.rb +1 -1
- data/spec/citeproc/extensions_spec.rb +9 -0
- data/spec/citeproc/processor_spec.rb +1 -1
- data/spec/citeproc/variable_spec.rb +168 -0
- metadata +119 -105
data/Gemfile
CHANGED
data/auto.watchr
CHANGED
@@ -11,7 +11,7 @@ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
|
|
11
11
|
|
12
12
|
def rspec (*paths)
|
13
13
|
paths = paths.reject { |p| !File.exists?(p) }
|
14
|
-
run "bundle exec rspec #{ paths.empty? ? 'spec' : paths.join(' ') }"
|
14
|
+
run "bundle exec rspec --tty -c #{ paths.empty? ? 'spec' : paths.join(' ') }"
|
15
15
|
end
|
16
16
|
|
17
17
|
def run (cmd)
|
data/lib/citeproc.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
require 'multi_json'
|
3
|
+
require 'forwardable'
|
4
|
+
|
2
5
|
|
3
6
|
require 'citeproc/version'
|
7
|
+
|
8
|
+
require 'citeproc/compatibility'
|
4
9
|
require 'citeproc/extensions'
|
10
|
+
|
5
11
|
require 'citeproc/errors'
|
12
|
+
|
6
13
|
require 'citeproc/abbreviate'
|
14
|
+
require 'citeproc/attributes'
|
15
|
+
require 'citeproc/variable'
|
16
|
+
require 'citeproc/date'
|
17
|
+
|
7
18
|
require 'citeproc/engine'
|
8
19
|
require 'citeproc/processor'
|
9
20
|
require 'citeproc/utilities'
|
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
module CiteProc
|
3
|
+
|
4
|
+
module Attributes
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
def attributes
|
12
|
+
@attributes ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def merge(other)
|
16
|
+
return self if other.nil?
|
17
|
+
|
18
|
+
case other
|
19
|
+
when String, /^\s*\{/
|
20
|
+
other = MulitJson.encode(other, :symbolize_keys => true)
|
21
|
+
when Hash
|
22
|
+
other = other.deep_copy
|
23
|
+
else
|
24
|
+
other = other.to_hash
|
25
|
+
end
|
26
|
+
|
27
|
+
other.each_pair { |k,v| attributes[k.to_sym] = v }
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
alias update merge
|
33
|
+
|
34
|
+
def reverse_merge(other)
|
35
|
+
other.merge(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
alias to_hash attributes
|
39
|
+
|
40
|
+
module ClassMethods
|
41
|
+
|
42
|
+
def create(parameters)
|
43
|
+
new.merge(parameters)
|
44
|
+
end
|
45
|
+
|
46
|
+
def attr_predicates(*arguments)
|
47
|
+
arguments.flatten.each do |field|
|
48
|
+
field, default = *(field.is_a?(Hash) ? field.to_a.flatten : [field]).map(&:to_s)
|
49
|
+
attr_field(field, default, true)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def attr_fields
|
54
|
+
arguments.flatten.each do |field|
|
55
|
+
attr_field(*(field.is_a?(Hash) ? field.to_a.flatten : [field]).map(&:to_s))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def attr_field(field, default = nil, predicate = false)
|
60
|
+
method_id = field.downcase.gsub(/[-\s]+/, '_')
|
61
|
+
|
62
|
+
unless instance_methods.include?(method_id)
|
63
|
+
if default
|
64
|
+
define_method(method_id) do
|
65
|
+
attributes[field.to_sym]
|
66
|
+
end
|
67
|
+
else
|
68
|
+
define_method(method_id) do
|
69
|
+
attributes[field.to_sym] ||= default
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
writer_id = [method_id,'='].join
|
75
|
+
unless instance_methods.include?(writer_id)
|
76
|
+
define_method(writer_id) do |value|
|
77
|
+
attributes[field.to_sym] = value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
predicate_id = [method_id, '?'].join
|
82
|
+
if predicate && !instance_methods.include?(predicate_id)
|
83
|
+
define_method(predicate_id) do
|
84
|
+
![nil, false, '', [], 'false', 'no', 'never'].include?(attributes[field.to_sym])
|
85
|
+
end
|
86
|
+
|
87
|
+
has_predicate = ['has_', predicate_id].join
|
88
|
+
alias_method(has_predicate, predicate_id) unless instance_methods.include?(has_predicate)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'chronic'
|
6
|
+
rescue LoadError => e
|
7
|
+
# warn 'failed to load chronic gem'
|
8
|
+
end
|
9
|
+
|
10
|
+
module CiteProc
|
11
|
+
|
12
|
+
class Date < Variable
|
13
|
+
|
14
|
+
include Attributes
|
15
|
+
|
16
|
+
alias attributes value
|
17
|
+
alias to_hash value
|
18
|
+
|
19
|
+
@parser = Object.const_defined?(:Chronic) ? ::Chronic : ::Date
|
20
|
+
|
21
|
+
class << self
|
22
|
+
|
23
|
+
def parse(date_string)
|
24
|
+
new(@parser.parse(date_string))
|
25
|
+
rescue => e
|
26
|
+
raise ArgumentError.new("failed to parse date from #{date_string.inspect}", e)
|
27
|
+
end
|
28
|
+
|
29
|
+
def today
|
30
|
+
new(::Date.today)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias now today
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def initialize(attributes = ::Date.today)
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_copy(other)
|
43
|
+
@value = other.value.deep_copy
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse(attributes)
|
47
|
+
case
|
48
|
+
when attributes.is_a?(Date)
|
49
|
+
@value = attributes.dup
|
50
|
+
|
51
|
+
when attributes.is_a?(Numeric)
|
52
|
+
@value = { :'date-parts' => [[attributes.to_i]] }
|
53
|
+
|
54
|
+
when attributes.is_a?(Hash)
|
55
|
+
attributes = attributes.symbolize_keys
|
56
|
+
if attributes.has_key?(:raw)
|
57
|
+
@value = Date.parse(attributes.delete(:raw)).value
|
58
|
+
@value.merge!(attributes)
|
59
|
+
else
|
60
|
+
@value = attributes.deep_copy
|
61
|
+
end
|
62
|
+
to_i!
|
63
|
+
|
64
|
+
when attributes.respond_to?(:strftime)
|
65
|
+
@value = { :'date-parts' => [attributes.strftime('%Y-%m-%d').split(/-/).map(&:to_i)] }
|
66
|
+
|
67
|
+
when attributes.is_a?(Array)
|
68
|
+
@value = { :'date-parts' => attributes[0].is_a?(Array) ? attributes : [attributes] }
|
69
|
+
to_i!
|
70
|
+
|
71
|
+
when attributes.respond_to?(:to_s)
|
72
|
+
@value = Date.parse(attributes.to_s).value
|
73
|
+
|
74
|
+
else
|
75
|
+
raise ArgumentError, "failed to parse date from #{attributes.inspect}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_predicates :circa, :season, :literal, :'date-parts'
|
80
|
+
|
81
|
+
def date_parts
|
82
|
+
@value[:'date-parts'] ||= [[]]
|
83
|
+
end
|
84
|
+
|
85
|
+
alias parts date_parts
|
86
|
+
alias parts= date_parts=
|
87
|
+
|
88
|
+
%w{ year month day }.each_with_index do |m,i|
|
89
|
+
define_method(m) { parts[0][i] }
|
90
|
+
define_method("#{m}=") { |v| parts[0][i] = v.to_i }
|
91
|
+
end
|
92
|
+
|
93
|
+
def start_date
|
94
|
+
::Date.new(*parts[0])
|
95
|
+
end
|
96
|
+
|
97
|
+
def start_date=(date)
|
98
|
+
parts[0] = date.strftime('%Y-%m-%d').split(/-/).map(&:to_i)
|
99
|
+
end
|
100
|
+
|
101
|
+
def end_date=(date)
|
102
|
+
parts[1] = date.nil? ? [0,0,0] : date.strftime('%Y-%m-%d').split(/-/).map(&:to_i)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a Ruby date object for this instance, or Range object if this
|
106
|
+
# instance is closed range
|
107
|
+
def to_ruby
|
108
|
+
closed_range? ? start_date ... end_date : start_date
|
109
|
+
end
|
110
|
+
|
111
|
+
def end_date
|
112
|
+
closed_range? ? ::Date.new(*parts[1]) : nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def has_end_date?
|
116
|
+
parts[1] && !parts[1].empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns true if this date is a range
|
120
|
+
alias range? has_end_date?
|
121
|
+
|
122
|
+
def open_range?
|
123
|
+
range? && parts[1].uniq == [0]
|
124
|
+
end
|
125
|
+
|
126
|
+
def closed_range?
|
127
|
+
range? && !open_range?
|
128
|
+
end
|
129
|
+
|
130
|
+
alias uncertain? circa?
|
131
|
+
|
132
|
+
# Marks the date as uncertain
|
133
|
+
def uncertain!; @value[:'circa'] = true; end
|
134
|
+
|
135
|
+
# Marks the date as a certain date
|
136
|
+
def certain!; @value[:'circa'] = false; end
|
137
|
+
|
138
|
+
def certain?; !uncertain?; end
|
139
|
+
|
140
|
+
def numeric?; false; end
|
141
|
+
|
142
|
+
def bc?; year && year < 0; end
|
143
|
+
def ad?; !bc? && year < 1000; end
|
144
|
+
|
145
|
+
def to_s
|
146
|
+
literal? ? literal : @value.inspect
|
147
|
+
end
|
148
|
+
|
149
|
+
def sort_order
|
150
|
+
"%04d%02d%02d-%04d%02d%02d" % ((parts[0] + [0,0,0])[0,3] + ((parts[1] || []) + [0,0,0])[0,3])
|
151
|
+
end
|
152
|
+
|
153
|
+
def <=>(other)
|
154
|
+
return nil unless other.is_a?(Date)
|
155
|
+
[year, sort_order] <=> [other.year, other.sort_order]
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def to_i!
|
161
|
+
parts.each { |p| p.map!(&:to_i) }
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
data/lib/citeproc/engine.rb
CHANGED
@@ -10,9 +10,11 @@ module CiteProc
|
|
10
10
|
@subclasses ||= []
|
11
11
|
|
12
12
|
class << self
|
13
|
-
|
13
|
+
|
14
14
|
attr_reader :subclasses, :type, :version
|
15
15
|
|
16
|
+
attr_writer :default
|
17
|
+
|
16
18
|
private :new
|
17
19
|
|
18
20
|
def inherited(subclass)
|
@@ -21,6 +23,10 @@ module CiteProc
|
|
21
23
|
@subclasses = subclasses.sort_by { |engine| -1 * engine.priority }
|
22
24
|
end
|
23
25
|
|
26
|
+
def default
|
27
|
+
@default ||= autodetect or warn 'no citeproc engine found'
|
28
|
+
end
|
29
|
+
|
24
30
|
# Returns the engine class for the given name or nil. If no suitable
|
25
31
|
# class is found and a block is given, executes the block and returns
|
26
32
|
# the result. The list of available engines will be passed to the block.
|
@@ -99,20 +105,26 @@ module CiteProc
|
|
99
105
|
raise NotImplementedByEngine
|
100
106
|
end
|
101
107
|
|
108
|
+
alias process_citation_cluster process
|
109
|
+
|
102
110
|
def append
|
103
111
|
raise NotImplementedByEngine
|
104
112
|
end
|
105
113
|
|
106
114
|
alias append_citation_cluster append
|
107
|
-
|
108
|
-
def
|
115
|
+
|
116
|
+
def preview
|
109
117
|
raise NotImplementedByEngine
|
110
118
|
end
|
111
|
-
|
112
|
-
|
119
|
+
|
120
|
+
alias preview_citation_cluster preview
|
121
|
+
|
122
|
+
def bibliography
|
113
123
|
raise NotImplementedByEngine
|
114
124
|
end
|
115
125
|
|
126
|
+
alias make_bibliography bibliography
|
127
|
+
|
116
128
|
def update_items
|
117
129
|
raise NotImplementedByEngine
|
118
130
|
end
|
data/lib/citeproc/errors.rb
CHANGED
@@ -8,10 +8,10 @@ module CiteProc
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
class EngineError < Error
|
12
|
-
end
|
11
|
+
class EngineError < Error; end
|
13
12
|
|
14
|
-
class NotImplementedByEngine < EngineError
|
15
|
-
|
13
|
+
class NotImplementedByEngine < EngineError; end
|
14
|
+
|
15
|
+
class ArgumentError < Error; end
|
16
16
|
|
17
17
|
end
|
data/lib/citeproc/extensions.rb
CHANGED
@@ -7,7 +7,7 @@ module CiteProc
|
|
7
7
|
Hash[*map { |k,v| [
|
8
8
|
k.is_a?(Symbol) ? k : k.respond_to?(:deep_copy) ? k.deep_copy : k.clone,
|
9
9
|
v.is_a?(Symbol) ? v : v.respond_to?(:deep_copy) ? v.deep_copy : v.clone
|
10
|
-
]}.flatten]
|
10
|
+
]}.flatten(1)]
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -23,6 +23,20 @@ module CiteProc
|
|
23
23
|
|
24
24
|
end
|
25
25
|
|
26
|
+
# shamelessly copied from active_support
|
27
|
+
module SymbolizeKeys
|
28
|
+
def symbolize_keys
|
29
|
+
inject({}) do |options, (key, value)|
|
30
|
+
options[(key.to_sym rescue key) || key] = value
|
31
|
+
options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def symbolize_keys!
|
36
|
+
replace(symbolize_keys)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
26
40
|
module AliasMethods
|
27
41
|
private
|
28
42
|
def alias_methods(*arguments)
|
@@ -37,6 +51,7 @@ end
|
|
37
51
|
class Hash
|
38
52
|
include CiteProc::Extensions::DeepCopy
|
39
53
|
include CiteProc::Extensions::DeepFetch
|
54
|
+
include CiteProc::Extensions::SymbolizeKeys unless Hash.instance_methods.include?(:symbolize_keys)
|
40
55
|
end
|
41
56
|
|
42
57
|
# module Kernel
|
data/lib/citeproc/processor.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
module CiteProc
|
3
3
|
class Processor
|
4
4
|
|
5
|
+
extend Forwardable
|
6
|
+
|
5
7
|
@defaults ||= {
|
6
8
|
:locale => 'en-US',
|
7
9
|
:style => 'chicago-author-date',
|
@@ -14,11 +16,14 @@ module CiteProc
|
|
14
16
|
end
|
15
17
|
|
16
18
|
attr_reader :options, :engine, :items
|
19
|
+
|
20
|
+
def_delegators :@engine, :process, :append, :preview, :bibliography, :style, :style=, :abbreviate, :abbreviations, :abbreviations=
|
17
21
|
|
18
22
|
def initialize(options = {})
|
19
23
|
@options = Processor.defaults.merge(options)
|
20
|
-
@engine = Engine.autodetect(@options).new
|
24
|
+
@engine = Engine.autodetect(@options).new(:processor => self)
|
25
|
+
@items = {}
|
21
26
|
end
|
22
27
|
|
23
28
|
end
|
24
|
-
end
|
29
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
|
2
|
+
module CiteProc
|
3
|
+
|
4
|
+
#
|
5
|
+
# A CiteProc Variable represents the content of a text, numeric, date, or
|
6
|
+
# name variable.
|
7
|
+
#
|
8
|
+
class Variable
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
include Comparable
|
13
|
+
|
14
|
+
@fields = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge({
|
15
|
+
:date => %w{ accessed container event-date issued original-date },
|
16
|
+
|
17
|
+
:names => %w{
|
18
|
+
author editor translator recipient interviewer publisher composer
|
19
|
+
original-publisher original-author container-author collection-editor },
|
20
|
+
|
21
|
+
:text => %w{
|
22
|
+
id abstract annote archive archive-location archive-place authority
|
23
|
+
call-number chapter-number citation-label citation-number collection-title
|
24
|
+
container-title DOI edition event event-place first-reference-note-number
|
25
|
+
genre ISBN issue jurisdiction keyword locator medium note number
|
26
|
+
number-of-pages number-of-volumes original-publisher original-publisher-place
|
27
|
+
original-title page page-first publisher publisher-place references
|
28
|
+
section status title URL version volume year-suffix }
|
29
|
+
})
|
30
|
+
|
31
|
+
@fields.each_value { |v| v.map!(&:to_sym) }
|
32
|
+
|
33
|
+
@types = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge(
|
34
|
+
Hash[*@fields.keys.map { |k| @fields[k].map { |n| [n,k] } }.flatten]
|
35
|
+
).freeze
|
36
|
+
|
37
|
+
@fields[:name] = @fields[:names]
|
38
|
+
@fields[:dates] = @fields[:date]
|
39
|
+
|
40
|
+
@fields[:all] = @fields[:any] =
|
41
|
+
[:date,:names,:text].reduce([]) { |s,a| s.concat(@fields[a]) }.sort
|
42
|
+
|
43
|
+
@fields.freeze
|
44
|
+
|
45
|
+
class << self
|
46
|
+
attr_reader :fields, :types
|
47
|
+
|
48
|
+
def parse(*args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(attributes = nil)
|
53
|
+
parse(attributes)
|
54
|
+
yield self if block_given?
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize_copy(other)
|
58
|
+
@value = other.value.dup
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_accessor :value
|
62
|
+
|
63
|
+
def_delegators :@value, :to_s, :strip!, :upcase!, :downcase!, :sub!, :gsub!, :chop!, :chomp!, :rstrip!
|
64
|
+
|
65
|
+
def_delegators :to_s, :empty?, :=~, :===, :match, :intern, :to_sym, :end_with?, :start_with?, :include?, :upcase, :downcase, :reverse, :chop, :chomp, :rstrip, :gsub, :sub, :size, :strip, :succ, :to_c, :to_r, :to_str, :split, :each_byte, :each_char, :each_line
|
66
|
+
|
67
|
+
def parse(attributes)
|
68
|
+
case
|
69
|
+
when attributes.is_a?(Hash)
|
70
|
+
attributes.each_key do |key|
|
71
|
+
writer = "#{key}="
|
72
|
+
send(writer, attributes[key]) if respond_to?(writer)
|
73
|
+
end
|
74
|
+
when attributes.respond_to?(:to_s)
|
75
|
+
@value = attributes.to_s.dup
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def type
|
80
|
+
@type ||= self.class.name.split(/::/)[-1].downcase.to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
def numeric?
|
84
|
+
self =~ /\d/ ? to_i : false
|
85
|
+
end
|
86
|
+
|
87
|
+
# @returns (first) numeric data contained in the variable's value
|
88
|
+
def to_i
|
89
|
+
to_s =~ /(-?\d+)/ && $1.to_i || 0
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_f
|
93
|
+
to_s =~ /(-?\d[\d,\.]*)/ && $1.tr(',','.').to_f || 0.0
|
94
|
+
end
|
95
|
+
|
96
|
+
def strip_markup
|
97
|
+
gsub(/<[^>]*>/, '')
|
98
|
+
end
|
99
|
+
|
100
|
+
def strip_markup!
|
101
|
+
gsub!(/<[^>]*>/, '')
|
102
|
+
end
|
103
|
+
|
104
|
+
def <=>(other)
|
105
|
+
case
|
106
|
+
when other.respond_to?(:strip_markup)
|
107
|
+
strip_markup <=> other.strip_markup
|
108
|
+
when other && other.respond_to?(:to_s)
|
109
|
+
to_s <=> other.to_s
|
110
|
+
else
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_json
|
116
|
+
MultiJson.encode(@value)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Text < Variable; end
|
121
|
+
end
|
data/lib/citeproc/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CiteProc
|
4
|
+
describe Attributes do
|
5
|
+
|
6
|
+
before(:each) { Object.instance_eval { include Attributes } }
|
7
|
+
|
8
|
+
let(:instance) { o = Object.new }
|
9
|
+
let(:other) { o = Object.new; o.attributes[:foo] = 'bar'; o }
|
10
|
+
|
11
|
+
it { should_not be_nil }
|
12
|
+
|
13
|
+
describe '.attr_fields' do
|
14
|
+
|
15
|
+
# before(:all) { class Object; attr_fields :value, %w[ is-numeric punctuation-mode ]; end }
|
16
|
+
|
17
|
+
it 'generates setters for attr_field values' do
|
18
|
+
# pending
|
19
|
+
# lambda { Object.new.is_numeric }.should_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'generates no other setters' do
|
23
|
+
lambda { Object.new.some_other_value }.should raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#merge' do
|
28
|
+
|
29
|
+
it 'merges non-existent values from other object' do
|
30
|
+
Object.new.merge(other).attributes[:foo].should == 'bar'
|
31
|
+
end
|
32
|
+
|
33
|
+
# it 'does not overwrite existing values when merging other object' do
|
34
|
+
# instance.merge(other)['foo'].should == 'bar'
|
35
|
+
# end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CiteProc
|
4
|
+
describe Date do
|
5
|
+
|
6
|
+
it { should_not be nil }
|
7
|
+
|
8
|
+
it { should_not be_numeric }
|
9
|
+
|
10
|
+
describe '.new' do
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.create' do
|
15
|
+
it 'should accept parameters and return a new instance' do
|
16
|
+
Date.create('date-parts' => [[2001, 1]]).year.should == 2001
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'literal dates' do
|
21
|
+
it 'is not literal by default' do
|
22
|
+
Date.new.should_not be_literal
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is literal if it contains only a literal field' do
|
26
|
+
Date.create(:literal => 'foo').should be_literal
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is literal if it contains a literal field' do
|
30
|
+
Date.create('date-parts' => [[2000]], :literal => 'foo').should be_literal
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'uncertain dates' do
|
35
|
+
it 'are uncertain' do
|
36
|
+
Date.new({ 'date-parts' => [[-225]], 'circa' => '1' }).should be_uncertain
|
37
|
+
Date.new { |d| d.parts = [[-225]]; d.uncertain! }.should be_uncertain
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'sorting' do
|
42
|
+
|
43
|
+
let(:ad2k) { Date.create('date-parts' => [[2000]])}
|
44
|
+
let(:may) { Date.create('date-parts' => [[2000, 5]])}
|
45
|
+
let(:first_of_may) { Date.create('date-parts' => [[2000, 5, 1]])}
|
46
|
+
|
47
|
+
let(:bc100) { Date.create('date-parts' => [[-100]]) }
|
48
|
+
let(:bc50) { Date.create('date-parts' => [[-50]]) }
|
49
|
+
let(:ad50) { Date.create('date-parts' => [[50]]) }
|
50
|
+
let(:ad100) { Date.create('date-parts' => [[100]]) }
|
51
|
+
|
52
|
+
it 'dates with more date-parts will come after those with fewer parts' do
|
53
|
+
(ad2k < may && may < first_of_may).should be true
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'negative years are sorted inversely' do
|
57
|
+
[ad50, bc100, bc50, ad100].sort.map(&:year).should == [-100, -50, 50, 100]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe '#display' do
|
63
|
+
it 'returns an empty string by default' do
|
64
|
+
Date.new({}).to_s == ''
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#to_json' do
|
69
|
+
it 'supports simple parts' do
|
70
|
+
Date.new(%w{2000 1 15}).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'supports integers and strings parts' do
|
74
|
+
Date.new(['2000', '1', '15']).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
75
|
+
Date.new([2000, 1, 15]).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
76
|
+
Date.new(['2000', 1, '15']).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'supports negative years' do
|
80
|
+
Date.new(-200).to_json.should == '{"date-parts":[[-200]]}'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'supports seasons' do
|
84
|
+
Date.create({:season => '1', 'date-parts' => [[1950]]}).to_json.should == '{"date-parts":[[1950]],"season":"1"}'
|
85
|
+
Date.create({:season => 'Trinity', 'date-parts' => [[1975]]}).to_json.should == '{"date-parts":[[1975]],"season":"Trinity"}'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'supports string literals' do
|
89
|
+
Date.new(:literal => '13th century').to_json.should == '{"literal":"13th century"}'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'supports raw strings' do
|
93
|
+
Date.new(:raw => '23 May 1955').to_json.should == '{"date-parts":[[1955,5,23]]}'
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'supports open and closed ranges' do
|
97
|
+
Date.new([[2000,11],[2000,12]]).to_json.should == '{"date-parts":[[2000,11],[2000,12]]}'
|
98
|
+
Date.new([[2000,11],[0,0]]).to_json.should == '{"date-parts":[[2000,11],[0,0]]}'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -22,6 +22,15 @@ describe Hash do
|
|
22
22
|
hash.deep_copy[:a][:b].should_not equal(hash[:a][:b])
|
23
23
|
hash.deep_copy[:a][:b][:c].should == hash[:a][:b][:c]
|
24
24
|
end
|
25
|
+
|
26
|
+
context 'when given nested arrays' do
|
27
|
+
let(:hash) {{:a => [[1,2]]}}
|
28
|
+
it 'it returns a deep copy' do
|
29
|
+
hash.deep_copy[:a].should == hash[:a]
|
30
|
+
hash.deep_copy[:a].should_not equal(hash[:a])
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
25
34
|
end
|
26
35
|
|
27
36
|
describe '#deep_fetch' do
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CiteProc
|
4
|
+
describe Variable do
|
5
|
+
|
6
|
+
describe '.new' do
|
7
|
+
it { should be_an_instance_of(Variable) }
|
8
|
+
|
9
|
+
it 'is empty by default' do
|
10
|
+
Variable.new.should be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'equals an empty string (==) by default' do
|
14
|
+
Variable.new.should == ''
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'matches an empty pattern by default' do
|
18
|
+
Variable.new.should =~ /^$/
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'accepts a string value' do
|
22
|
+
Variable.new('test').should == 'test'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'accepts a numeric value' do
|
26
|
+
Variable.new(23).should == '23'
|
27
|
+
Variable.new(23.1).should == '23.1'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'accepts an attributes hash' do
|
31
|
+
Variable.new(:value => 'test').should == 'test'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'supports self yielding block' do
|
35
|
+
Variable.new { |v| v.value = 'test' }.should == 'test'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.fields' do
|
40
|
+
it 'contains :names fields' do
|
41
|
+
Variable.fields[:names].should_not be_empty
|
42
|
+
Variable.fields[:name].should equal Variable.fields[:names]
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'contains :date fields' do
|
46
|
+
Variable.fields[:date].should_not be_empty
|
47
|
+
Variable.fields[:dates].should equal Variable.fields[:date]
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'contains :text fields' do
|
51
|
+
Variable.fields[:text].should_not be_empty
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'accepts either string or symbol input' do
|
55
|
+
Variable.fields[:names].should equal Variable.fields['names']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '.types' do
|
60
|
+
it 'given a field name returns the corresponding type' do
|
61
|
+
Variable.types[:author].should == :names
|
62
|
+
Variable.types[:issued].should == :date
|
63
|
+
Variable.types[:abstract].should == :text
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'accepts either string or symbol input' do
|
67
|
+
Variable.types.should have_key(:author)
|
68
|
+
Variable.types['author'].should equal Variable.types[:author]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#to_s' do
|
73
|
+
it 'displays the value' do
|
74
|
+
Variable.new('test').to_s.should == 'test'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#to_i' do
|
79
|
+
it 'returns zero by default' do
|
80
|
+
Variable.new.to_i.should == 0
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the value is numeric' do
|
84
|
+
%w{ -23 -1 0 1 23 }.each do |value|
|
85
|
+
it "returns the integer value (#{value})" do
|
86
|
+
Variable.new(value).to_i.should equal(value.to_i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'returns only the first numeric value if there are several' do
|
91
|
+
Variable.new('testing 1, 2, 3...').to_i.should == 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#to_f' do
|
97
|
+
it 'returns zero by default' do
|
98
|
+
Variable.new.to_f.should == 0.0
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when the value is numeric' do
|
102
|
+
%w{ -23.2 -1.45 0.2 1.733 23 }.each do |value|
|
103
|
+
it "returns the integer value (#{value})" do
|
104
|
+
Variable.new(value).to_f.should == value.to_f
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns only the first numeric value if there are several' do
|
109
|
+
Variable.new('testing 1, 2, 3...').to_f.should == 1.0
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'works with dot and comma separators' do
|
113
|
+
Variable.new('1,23').to_f.should == Variable.new('1.23').to_f
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#numeric?' do
|
119
|
+
it 'returns false by default' do
|
120
|
+
Variable.new.should_not be_numeric
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'variable contains a number' do
|
124
|
+
it 'returns true (string initialized)' do
|
125
|
+
Variable.new('23').should be_numeric
|
126
|
+
Variable.new('foo 23').should be_numeric
|
127
|
+
end
|
128
|
+
it 'returns true (integer initialized)' do
|
129
|
+
Variable.new(23).should be_numeric
|
130
|
+
end
|
131
|
+
end
|
132
|
+
context 'variable does not contain a number' do
|
133
|
+
it 'returns false for strings' do
|
134
|
+
Variable.new('test').should_not be_numeric
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#strip_markup' do
|
140
|
+
let(:greeting) { '<h1>hello<b> world</b></h1>' }
|
141
|
+
it 'returns a string stripped of html tags' do
|
142
|
+
Variable.new(greeting).strip_markup.should == 'hello world'
|
143
|
+
end
|
144
|
+
it 'does not alter the value itself' do
|
145
|
+
v = Variable.new(greeting)
|
146
|
+
v.strip_markup
|
147
|
+
v.should == greeting
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#strip_markup!' do
|
152
|
+
let(:greeting) { '<h1>hello<b> world</b></h1>' }
|
153
|
+
it 'strips of html tags' do
|
154
|
+
v = Variable.new(greeting)
|
155
|
+
v.strip_markup!
|
156
|
+
v.should == 'hello world'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
describe 'sorting' do
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#to_json' do
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
metadata
CHANGED
@@ -1,126 +1,140 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: citeproc
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease:
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
- Sylvester Keil
|
7
|
+
authors:
|
8
|
+
- Sylvester Keil
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
12
|
+
|
13
|
+
date: 2011-08-08 00:00:00 +02:00
|
13
14
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: multi_json
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "1.0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: cucumber
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.0.2
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.6.0
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: watchr
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0.7"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
59
60
|
description: A a cite processor for Citation Style Language (CSL) styles.
|
60
61
|
email: http://sylvester.keil.or.at
|
61
62
|
executables: []
|
63
|
+
|
62
64
|
extensions: []
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
- .
|
68
|
-
-
|
69
|
-
-
|
70
|
-
-
|
71
|
-
-
|
72
|
-
-
|
73
|
-
-
|
74
|
-
- lib/citeproc
|
75
|
-
- lib/citeproc/
|
76
|
-
- lib/citeproc/
|
77
|
-
- lib/citeproc/
|
78
|
-
- lib/citeproc/
|
79
|
-
- lib/citeproc/
|
80
|
-
- lib/citeproc/
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
-
|
85
|
-
-
|
86
|
-
- spec/
|
65
|
+
|
66
|
+
extra_rdoc_files:
|
67
|
+
- README.md
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE
|
73
|
+
- README.md
|
74
|
+
- auto.watchr
|
75
|
+
- citeproc.gemspec
|
76
|
+
- lib/citeproc.rb
|
77
|
+
- lib/citeproc/abbreviate.rb
|
78
|
+
- lib/citeproc/attributes.rb
|
79
|
+
- lib/citeproc/compatibility.rb
|
80
|
+
- lib/citeproc/date.rb
|
81
|
+
- lib/citeproc/engine.rb
|
82
|
+
- lib/citeproc/errors.rb
|
83
|
+
- lib/citeproc/extensions.rb
|
84
|
+
- lib/citeproc/processor.rb
|
85
|
+
- lib/citeproc/utilities.rb
|
86
|
+
- lib/citeproc/variable.rb
|
87
|
+
- lib/citeproc/version.rb
|
88
|
+
- spec/citeproc/abbreviate_spec.rb
|
89
|
+
- spec/citeproc/attributes_spec.rb
|
90
|
+
- spec/citeproc/date_spec.rb
|
91
|
+
- spec/citeproc/engine_spec.rb
|
92
|
+
- spec/citeproc/extensions_spec.rb
|
93
|
+
- spec/citeproc/processor_spec.rb
|
94
|
+
- spec/citeproc/utilities_spec.rb
|
95
|
+
- spec/citeproc/variable_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
87
97
|
has_rdoc: true
|
88
98
|
homepage: http://inukshuk.github.com/citeproc
|
89
|
-
licenses:
|
90
|
-
- FreeBSD
|
99
|
+
licenses:
|
100
|
+
- FreeBSD
|
91
101
|
post_install_message:
|
92
|
-
rdoc_options:
|
93
|
-
- --line-numbers
|
94
|
-
- --inline-source
|
95
|
-
- --title
|
96
|
-
-
|
97
|
-
- --main
|
98
|
-
- README.md
|
99
|
-
- --webcvs=http://github.com/inukshuk/citeproc/tree/master/
|
100
|
-
require_paths:
|
101
|
-
- lib
|
102
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
rdoc_options:
|
103
|
+
- --line-numbers
|
104
|
+
- --inline-source
|
105
|
+
- --title
|
106
|
+
- "\"CiteProc\""
|
107
|
+
- --main
|
108
|
+
- README.md
|
109
|
+
- --webcvs=http://github.com/inukshuk/citeproc/tree/master/
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
113
|
none: false
|
104
|
-
requirements:
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: "0"
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
119
|
none: false
|
110
|
-
requirements:
|
111
|
-
|
112
|
-
|
113
|
-
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: "0"
|
114
124
|
requirements: []
|
125
|
+
|
115
126
|
rubyforge_project:
|
116
|
-
rubygems_version: 1.
|
127
|
+
rubygems_version: 1.5.1
|
117
128
|
signing_key:
|
118
129
|
specification_version: 3
|
119
130
|
summary: A cite processor interface.
|
120
|
-
test_files:
|
121
|
-
- spec/citeproc/abbreviate_spec.rb
|
122
|
-
- spec/citeproc/
|
123
|
-
- spec/citeproc/
|
124
|
-
- spec/citeproc/
|
125
|
-
- spec/citeproc/
|
126
|
-
- spec/
|
131
|
+
test_files:
|
132
|
+
- spec/citeproc/abbreviate_spec.rb
|
133
|
+
- spec/citeproc/attributes_spec.rb
|
134
|
+
- spec/citeproc/date_spec.rb
|
135
|
+
- spec/citeproc/engine_spec.rb
|
136
|
+
- spec/citeproc/extensions_spec.rb
|
137
|
+
- spec/citeproc/processor_spec.rb
|
138
|
+
- spec/citeproc/utilities_spec.rb
|
139
|
+
- spec/citeproc/variable_spec.rb
|
140
|
+
- spec/spec_helper.rb
|