citeproc 0.0.3 → 0.0.6
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/lib/citeproc.rb +34 -0
- data/lib/citeproc/abbreviate.rb +29 -25
- data/lib/citeproc/assets.rb +101 -61
- data/lib/citeproc/bibliography.rb +188 -169
- data/lib/citeproc/engine.rb +28 -47
- data/lib/citeproc/item.rb +117 -108
- data/lib/citeproc/processor.rb +102 -35
- data/lib/citeproc/utilities.rb +3 -2
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/assets_spec.rb +59 -55
- data/spec/citeproc/bibliography_spec.rb +67 -67
- data/spec/citeproc/engine_spec.rb +2 -6
- data/spec/citeproc/processor_spec.rb +73 -1
- metadata +10 -10
data/lib/citeproc/engine.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module CiteProc
|
4
|
-
|
4
|
+
|
5
5
|
class Engine
|
6
|
-
|
7
6
|
extend Forwardable
|
8
|
-
|
9
|
-
|
7
|
+
|
8
|
+
include Converters
|
9
|
+
|
10
10
|
@subclasses ||= []
|
11
11
|
|
12
12
|
class << self
|
13
|
-
|
13
|
+
|
14
14
|
attr_reader :subclasses, :type, :version
|
15
|
-
|
15
|
+
|
16
16
|
attr_writer :default
|
17
|
-
|
17
|
+
|
18
18
|
private :new
|
19
|
-
|
19
|
+
|
20
20
|
def inherited(subclass)
|
21
21
|
subclass.public_class_method :new
|
22
22
|
@subclasses << subclass
|
@@ -34,33 +34,33 @@ module CiteProc
|
|
34
34
|
subclasses.detect { |e| e.name == name } ||
|
35
35
|
block_given? ? yield(subclasses) : nil
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
# Loads the engine with the given name and returns the engine class.
|
39
39
|
def detect!(name)
|
40
40
|
load(name)
|
41
41
|
block_given? ? detect(name, &Proc.new) : detect(name)
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
# Returns the best available engine class or nil.
|
45
45
|
def autodetect(options = {})
|
46
46
|
subclasses.detect { |e|
|
47
47
|
!options.has_key?(:engine) || e.name == options[:engine] and
|
48
48
|
!options.has_key?(:name) || e.name == options[:name]
|
49
|
-
} || subclasses.first
|
49
|
+
} || subclasses.first
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# Loads the engine by requiring the engine name.
|
53
53
|
def load(name)
|
54
54
|
require name.gsub(/-/,'/')
|
55
55
|
rescue LoadError
|
56
56
|
warn "failed to load #{name} engine: try to gem install #{name}"
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Returns a list of all available engine names.
|
60
60
|
def available
|
61
61
|
subclasses.map(&:engine_name)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def engine_name
|
65
65
|
@name ||= name.gsub(/::/, '-').downcase # returns class name as fallback
|
66
66
|
end
|
@@ -70,64 +70,45 @@ module CiteProc
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
attr_accessor :processor
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
@
|
80
|
-
|
73
|
+
attr_accessor :processor
|
74
|
+
|
75
|
+
def_delegators :@processor, :options, :abbreviations, :style, :locale,
|
76
|
+
:items, :language, :region, :abbreviate
|
77
|
+
|
78
|
+
def initialize(processor = nil)
|
79
|
+
@processor = processor
|
81
80
|
yield self if block_given?
|
82
81
|
end
|
83
82
|
|
84
|
-
def start
|
85
|
-
@started = true
|
86
|
-
self
|
87
|
-
end
|
88
|
-
|
89
|
-
def stop
|
90
|
-
@started = false
|
91
|
-
self
|
92
|
-
end
|
93
|
-
|
94
|
-
def started?; !!@started; end
|
95
|
-
|
96
|
-
alias running? started?
|
97
|
-
|
98
83
|
[[:name, :engine_name], :type, :version].each do |method_id, target|
|
99
84
|
define_method(method_id) do
|
100
85
|
self.class.send(target || method_id)
|
101
86
|
end
|
102
87
|
end
|
103
|
-
|
88
|
+
|
104
89
|
def process
|
105
90
|
raise NotImplementedByEngine
|
106
91
|
end
|
107
|
-
|
108
|
-
alias process_citation_cluster process
|
109
92
|
|
110
93
|
def append
|
111
94
|
raise NotImplementedByEngine
|
112
95
|
end
|
113
|
-
|
114
|
-
alias append_citation_cluster append
|
115
96
|
|
116
|
-
|
117
97
|
def bibliography
|
118
98
|
raise NotImplementedByEngine
|
119
99
|
end
|
120
|
-
|
121
|
-
alias make_bibliography bibliography
|
122
|
-
|
100
|
+
|
123
101
|
def update_items
|
124
102
|
raise NotImplementedByEngine
|
125
103
|
end
|
126
|
-
|
104
|
+
|
127
105
|
def update_uncited_items
|
128
106
|
raise NotImplementedByEngine
|
129
107
|
end
|
130
|
-
|
108
|
+
|
109
|
+
def inspect
|
110
|
+
"#<CiteProc::Engine #{name}-#{type}-#{version}>"
|
111
|
+
end
|
131
112
|
end
|
132
113
|
|
133
114
|
end
|
data/lib/citeproc/item.rb
CHANGED
@@ -1,113 +1,122 @@
|
|
1
1
|
module CiteProc
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@types = [
|
27
|
-
:article, :'article-journal', :'article-magazine', :'article-newspaper',
|
28
|
-
:bill, :book, :broadcast, :chapter, :entry, :'entry-dictionary',
|
29
|
-
:'entry-encyclopedia', :figure, :graphic, :interview, :legal_case,
|
30
|
-
:legislation, :manuscript, :map, :motion_picture, :musical_score,
|
31
|
-
:pamphlet, :'paper-conference', :patent, :personal_communication, :post,
|
32
|
-
:'post-weblog', :report, :review, :'review-book', :song, :speech,
|
33
|
-
:thesis, :treaty, :webpage].freeze
|
34
|
-
|
35
|
-
@bibtex_types = Hash.new { |h,k| :misc }.merge(Hash[*%w{
|
36
|
-
pamphlet booklet
|
37
|
-
paper-conference conference
|
38
|
-
chapter inbook
|
39
|
-
chapter incollection
|
40
|
-
paper-conference inproceedings
|
41
|
-
book manual
|
42
|
-
thesis phdthesis
|
43
|
-
paper-conference proceedings
|
44
|
-
report techreport
|
45
|
-
manuscript unpublished
|
46
|
-
article article
|
47
|
-
article-journal article
|
48
|
-
article-magazine article
|
49
|
-
}.map(&:intern)]).freeze
|
50
|
-
|
51
|
-
class << self
|
52
|
-
attr_reader :types, :bibtex_types
|
53
|
-
end
|
54
|
-
|
55
|
-
include Attributes
|
56
|
-
include Enumerable
|
57
|
-
|
58
|
-
attr_predicates :id, :'short-title', :'journal-abbreviation',
|
59
|
-
*Variable.fields[:all]
|
60
|
-
|
61
|
-
def initialize(attributes = nil)
|
62
|
-
merge(attributes)
|
63
|
-
end
|
64
|
-
|
65
|
-
def initialize_copy(other)
|
66
|
-
@attributes = other.attributes.deep_copy
|
67
|
-
end
|
2
|
+
|
3
|
+
|
4
|
+
# Items are similar to a Ruby Hash but pose a number of constraints on their
|
5
|
+
# contents: keys are always (implicitly converted to) symbols and values
|
6
|
+
# are strictly instances of CiteProc::Variable. When Items are constructed
|
7
|
+
# from (or merged with) JSON objects or Hashes Variable instances are
|
8
|
+
# automatically created using by passing the variables key as type to
|
9
|
+
# Variable.create – this will create the expected Variable type for all
|
10
|
+
# fields defined in CSL (for example, the `issued' field will become a
|
11
|
+
# CiteProc::Date object); unknown types will be converted to simple
|
12
|
+
# CiteProc::Variable instances, which should be fine for numeric or string
|
13
|
+
# values but may cause problems for more complex types.
|
14
|
+
#
|
15
|
+
# Every Item provides accessor methods for all known field names; unknown
|
16
|
+
# fields can still be accessed using array accessor syntax.
|
17
|
+
#
|
18
|
+
# i = Item.new(:edition => 3, :unknown_field => 42)
|
19
|
+
# i.edition -> #<CiteProc::Number "3">
|
20
|
+
# i[:edition] -> #<CiteProc::Number "3">
|
21
|
+
# i[:unknown_field] -> #<CiteProc::Variable "42">
|
22
|
+
#
|
23
|
+
# Items can be converted to the CiteProc JSON format via #to_citeproc (or
|
24
|
+
# #to_json to get a JSON string).
|
25
|
+
class Item
|
68
26
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
27
|
+
@types = [
|
28
|
+
:article, :'article-journal', :'article-magazine', :'article-newspaper',
|
29
|
+
:bill, :book, :broadcast, :chapter, :entry, :'entry-dictionary',
|
30
|
+
:'entry-encyclopedia', :figure, :graphic, :interview, :legal_case,
|
31
|
+
:legislation, :manuscript, :map, :motion_picture, :musical_score,
|
32
|
+
:pamphlet, :'paper-conference', :patent, :personal_communication, :post,
|
33
|
+
:'post-weblog', :report, :review, :'review-book', :song, :speech,
|
34
|
+
:thesis, :treaty, :webpage].freeze
|
35
|
+
|
36
|
+
@bibtex_types = Hash.new { |h,k| :misc }.merge(Hash[*%w{
|
37
|
+
pamphlet booklet
|
38
|
+
paper-conference conference
|
39
|
+
chapter inbook
|
40
|
+
chapter incollection
|
41
|
+
paper-conference inproceedings
|
42
|
+
book manual
|
43
|
+
thesis phdthesis
|
44
|
+
paper-conference proceedings
|
45
|
+
report techreport
|
46
|
+
manuscript unpublished
|
47
|
+
article article
|
48
|
+
article-journal article
|
49
|
+
article-magazine article
|
50
|
+
}.map(&:intern)]).freeze
|
51
|
+
|
52
|
+
class << self
|
53
|
+
attr_reader :types, :bibtex_types
|
54
|
+
end
|
55
|
+
|
56
|
+
include Attributes
|
57
|
+
include Enumerable
|
58
|
+
|
59
|
+
attr_predicates :id, :'short-title', :'journal-abbreviation',
|
60
|
+
*Variable.fields[:all]
|
61
|
+
|
62
|
+
def initialize(attributes = nil)
|
63
|
+
merge(attributes)
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize_copy(other)
|
67
|
+
@attributes = other.attributes.deep_copy
|
68
|
+
end
|
69
|
+
|
70
|
+
# Don't expose attributes. Items need to mimic Hash functionality in a controlled way.
|
71
|
+
private :attributes
|
72
|
+
|
73
|
+
def each
|
74
|
+
if block_given?
|
75
|
+
attributes.each(&Proc.new)
|
76
|
+
self
|
77
|
+
else
|
78
|
+
to_enum
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns a corresponding BibTeX::Entry if the bibtex-ruby gem is installed;
|
83
|
+
# otherwise returns a BibTeX string.
|
84
|
+
def to_bibtex
|
85
|
+
# hash = to_hash
|
86
|
+
#
|
87
|
+
# hash[:type] = Item.bibtex_types[hash[:type]]
|
88
|
+
#
|
89
|
+
# if hash.has_key?(:issued)
|
90
|
+
# date = hash.delete(:issued)
|
91
|
+
# hash[:year] = date.year
|
92
|
+
# hash[:month] = date.month
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# Variable.fields[:date].each do |field|
|
96
|
+
# hash[field] = hash[field].to_s if hash.has_key?(field)
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# Variable.fields[:names].each do |field|
|
100
|
+
# hash[field] = hash[field].to_bibtex
|
101
|
+
# end
|
102
|
+
|
103
|
+
raise 'not implemented yet'
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_sym
|
107
|
+
id.to_s.to_sym
|
108
|
+
end
|
109
|
+
|
110
|
+
def inspect
|
111
|
+
"#<CiteProc::Item id=#{id.inspect} attributes={#{attributes.length}}>"
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
110
115
|
|
111
|
-
|
116
|
+
def filter_value(value, key)
|
117
|
+
Variable.create!(value, key)
|
118
|
+
end
|
112
119
|
|
120
|
+
end
|
121
|
+
|
113
122
|
end
|
data/lib/citeproc/processor.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
|
2
2
|
module CiteProc
|
3
|
+
|
3
4
|
class Processor
|
4
|
-
|
5
5
|
extend Forwardable
|
6
|
+
|
7
|
+
include Abbreviate
|
8
|
+
include Converters
|
6
9
|
|
7
10
|
@defaults = {
|
8
11
|
:locale => 'en-US',
|
@@ -15,41 +18,105 @@ module CiteProc
|
|
15
18
|
attr_reader :defaults
|
16
19
|
end
|
17
20
|
|
18
|
-
attr_reader :options, :
|
21
|
+
attr_reader :options, :items
|
22
|
+
attr_writer :engine
|
23
|
+
|
24
|
+
def_delegators :@locale, :language, :region
|
25
|
+
|
26
|
+
def_delegators :@items, :key?, :value?, :has_key?, :has_value?,
|
27
|
+
:include?, :member?, :length, :empty?
|
19
28
|
|
20
|
-
def_delegators :@engine, :abbreviate, :abbreviations, :abbreviations=
|
21
|
-
|
22
29
|
def initialize(options = {})
|
23
|
-
@options = Processor.defaults.merge(options)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
30
|
+
@options, @items = Processor.defaults.merge(options), {}
|
31
|
+
yield self if block_given?
|
32
|
+
end
|
33
|
+
|
34
|
+
def engine
|
35
|
+
@engine ||= Engine.autodetect(options).new(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def style
|
39
|
+
@style || load_style
|
40
|
+
end
|
41
|
+
|
42
|
+
def locale
|
43
|
+
@locale || load_locale
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_style(new_style = nil)
|
47
|
+
options[:style] = new_style unless new_style.nil?
|
48
|
+
@style = Style.open(options[:style])
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_locale(new_locale = nil)
|
52
|
+
options[:locale] = new_locale unless new_locale.nil?
|
53
|
+
@locale = Locale.open(options[:locale])
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](id)
|
57
|
+
items[id.to_sym]
|
58
|
+
end
|
59
|
+
|
60
|
+
def []=(id, item)
|
61
|
+
items[id.to_sym] = Item(item)
|
62
|
+
end
|
63
|
+
|
64
|
+
def register(item)
|
65
|
+
item = Item(item)
|
66
|
+
items[item.to_sym] = item
|
67
|
+
rescue => e
|
68
|
+
raise "failed to register item #{item.inspect}: #{e.message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def <<(item)
|
72
|
+
register(item)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def update(*arguments)
|
77
|
+
arguments.flatten(1).each do |argument|
|
78
|
+
case argument
|
79
|
+
when Item
|
80
|
+
register(argument)
|
81
|
+
when Array
|
82
|
+
argument.each { |item| register(item) }
|
83
|
+
when Hash
|
84
|
+
argument.each do |id, item|
|
85
|
+
id, item = id.to_sym, Item(item)
|
86
|
+
|
87
|
+
if items.key?(id) && block_given?
|
88
|
+
items[id] = yield items[id], item
|
89
|
+
else
|
90
|
+
items[id] = item
|
91
|
+
end
|
92
|
+
end
|
93
|
+
else
|
94
|
+
raise "failed to register items #{argument.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
self
|
99
|
+
ensure
|
100
|
+
# notify engine
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
def process(*arguments)
|
106
|
+
engine.process(CitationData(arguments.flatten(1)))
|
107
|
+
end
|
108
|
+
|
109
|
+
def append(*arguments)
|
110
|
+
engine.append(CitationData(arguments.flatten(1)))
|
111
|
+
end
|
112
|
+
|
113
|
+
def bibliography(*arguments, &block)
|
114
|
+
engine.bibliography(Selector.new(*arguments, &block))
|
115
|
+
end
|
116
|
+
|
117
|
+
def inspect
|
118
|
+
"#<CiteProc::Processor style=#{style.name.inspect} locale=#{locale.name.inspect} items=[#{items.length}]>"
|
119
|
+
end
|
120
|
+
|
54
121
|
end
|
55
122
|
end
|