citeproc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,2 +1,11 @@
1
1
  source :rubygems
2
2
  gemspec
3
+
4
+ group :debug do
5
+ gem 'ruby-debug', :platforms => [:ruby_18, :jruby]
6
+ gem 'ruby-debug19', :require => 'ruby-debug', :platforms => [:ruby_19]
7
+ end
8
+
9
+ group :optional do
10
+ gem 'chronic', '~>0.6'
11
+ end
@@ -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)
@@ -1,9 +1,20 @@
1
- require 'rubygems'
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,10 @@
1
+ unless Symbol.is_a?(Comparable)
2
+ class Symbol
3
+ include Comparable
4
+
5
+ def <=>(other)
6
+ return nil unless other.respond_to?(:to_s)
7
+ to_s <=> other.to_s
8
+ end
9
+ end
10
+ 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
@@ -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 process_citation_cluster
115
+
116
+ def preview
109
117
  raise NotImplementedByEngine
110
118
  end
111
-
112
- def make_bibliography
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
@@ -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
- end
13
+ class NotImplementedByEngine < EngineError; end
14
+
15
+ class ArgumentError < Error; end
16
16
 
17
17
  end
@@ -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
@@ -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 :processor => self
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
@@ -1,3 +1,3 @@
1
1
  module CiteProc
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module CiteProc
4
- describe 'Abbreviate' do
4
+ describe Abbreviate do
5
5
  before { Object.class_eval { include Abbreviate } }
6
6
 
7
7
  let(:subject) { Object.new }
@@ -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
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module CiteProc
4
- describe 'Engine' do
4
+ describe Engine do
5
5
 
6
6
  it 'cannot be instantiated' do
7
7
  lambda { Engine.new }.should raise_error(NoMethodError)
@@ -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
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module CiteProc
4
- describe 'Processor' do
4
+ describe Processor do
5
5
  before { Class.new(Engine) }
6
6
 
7
7
  let(:subject) { Processor.new }
@@ -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
- date: 2011-08-03 00:00:00.000000000 +02:00
12
+
13
+ date: 2011-08-08 00:00:00 +02:00
13
14
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: multi_json
17
- requirement: &2157053340 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ~>
21
- - !ruby/object:Gem::Version
22
- version: '1.0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: *2157053340
26
- - !ruby/object:Gem::Dependency
27
- name: cucumber
28
- requirement: &2157052700 !ruby/object:Gem::Requirement
29
- none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
33
- version: 1.0.2
34
- type: :development
35
- prerelease: false
36
- version_requirements: *2157052700
37
- - !ruby/object:Gem::Dependency
38
- name: rspec
39
- requirement: &2157052100 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: 2.6.0
45
- type: :development
46
- prerelease: false
47
- version_requirements: *2157052100
48
- - !ruby/object:Gem::Dependency
49
- name: watchr
50
- requirement: &2157051560 !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0.7'
56
- type: :development
57
- prerelease: false
58
- version_requirements: *2157051560
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
- extra_rdoc_files:
64
- - README.md
65
- files:
66
- - .gitignore
67
- - .rspec
68
- - Gemfile
69
- - LICENSE
70
- - README.md
71
- - auto.watchr
72
- - citeproc.gemspec
73
- - lib/citeproc.rb
74
- - lib/citeproc/abbreviate.rb
75
- - lib/citeproc/engine.rb
76
- - lib/citeproc/errors.rb
77
- - lib/citeproc/extensions.rb
78
- - lib/citeproc/processor.rb
79
- - lib/citeproc/utilities.rb
80
- - lib/citeproc/version.rb
81
- - spec/citeproc/abbreviate_spec.rb
82
- - spec/citeproc/engine_spec.rb
83
- - spec/citeproc/extensions_spec.rb
84
- - spec/citeproc/processor_spec.rb
85
- - spec/citeproc/utilities_spec.rb
86
- - spec/spec_helper.rb
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
- - ! '"CiteProc"'
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
- - !ruby/object:Gem::Version
107
- version: '0'
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
- - !ruby/object:Gem::Version
113
- version: '0'
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: "0"
114
124
  requirements: []
125
+
115
126
  rubyforge_project:
116
- rubygems_version: 1.6.2
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/engine_spec.rb
123
- - spec/citeproc/extensions_spec.rb
124
- - spec/citeproc/processor_spec.rb
125
- - spec/citeproc/utilities_spec.rb
126
- - spec/spec_helper.rb
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