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