pinpoint 0.0.3 → 0.1.0

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.
@@ -1,3 +1,3 @@
1
1
  module Pinpoint
2
- VERSION = '0.0.3'
2
+ VERSION = '0.1.0'
3
3
  end
data/spec/address_spec.rb CHANGED
@@ -1,4 +1,5 @@
1
- require 'spec_helper'
1
+ require 'rspectacular'
2
+ require 'pinpoint/address'
2
3
 
3
4
  describe 'Pinpoint::Address' do
4
5
  let(:address) { Pinpoint::Address.new }
@@ -7,6 +8,8 @@ describe 'Pinpoint::Address' do
7
8
  it { address.respond_to?(:region=).should be_true }
8
9
  it { address.respond_to?(:province).should be_true }
9
10
  it { address.respond_to?(:province=).should be_true }
11
+ it { address.respond_to?(:locality).should be_true }
12
+ it { address.respond_to?(:locality=).should be_true }
10
13
  it { address.respond_to?(:postal_code).should be_true }
11
14
  it { address.respond_to?(:postal_code=).should be_true }
12
15
  it { address.respond_to?(:postalcode).should be_true }
@@ -0,0 +1,24 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/file'
3
+
4
+ describe Pinpoint::Format::File do
5
+ let(:file_class) { Pinpoint::Format::File }
6
+
7
+ it 'can retrieve Styles for a given country' do
8
+ File.should_receive(:read).and_return <<-FORMAT_YAML
9
+ one_line: 'foo'
10
+ multi_line: 'bar'
11
+ html: 'baz'
12
+ FORMAT_YAML
13
+
14
+ styles = file_class.styles_for(:us)
15
+
16
+ styles.keys.should eql [
17
+ :one_line,
18
+ :multi_line,
19
+ :html
20
+ ]
21
+
22
+ styles.values.should be_all { |s| s.class == Pinpoint::Format::Style }
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/list'
3
+
4
+ describe Pinpoint::Format::List do
5
+ let(:format_list_class) { Pinpoint::Format::List }
6
+ let(:format_list) { format_list_class.new }
7
+
8
+ it 'can find formats for a country that it has not already loaded' do
9
+ Pinpoint::Format.should_receive(:lookup_by_country)
10
+ .with(:us)
11
+
12
+ format_list[:us]
13
+ end
14
+
15
+ it 'can memoize formats for performance' do
16
+ Pinpoint::Format.should_receive(:lookup_by_country)
17
+ .once
18
+ .with(:us)
19
+ .and_return('format')
20
+
21
+ format_list[:us]
22
+ format_list[:us]
23
+ end
24
+ end
@@ -0,0 +1,60 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/parser'
3
+
4
+ describe Pinpoint::Format::Parser do
5
+ let(:parser_class) { Pinpoint::Format::Parser }
6
+ let(:parsable_string) { '(%s, )((%l, )(%p )%z)(, %c)' }
7
+ let(:parser) { parser_class.new(parsable_string) }
8
+
9
+ context 'when the parsable string contains literal parenthesis' do
10
+ let(:parsable_string) { '%)%((%((%))%)%%%))' }
11
+
12
+ it 'can properly parse a string' do
13
+ parser.parse.should eql [
14
+ ')',
15
+ '(',
16
+ [
17
+ '(',
18
+ [
19
+ ')'
20
+ ],
21
+ ')',
22
+ '%',
23
+ ')'
24
+ ]
25
+ ]
26
+ end
27
+ end
28
+
29
+ it 'checks that the token set is valid before attempting to process it' do
30
+ parser.send(:tokens).should_receive :valid?
31
+
32
+ parser.parse
33
+ end
34
+
35
+ context 'when the parsable string is typical' do
36
+ it 'can properly parse a string' do
37
+ parser.parse.should eql [
38
+ [
39
+ :street,
40
+ ', ',
41
+ ],
42
+ [
43
+ [
44
+ :locality,
45
+ ', '
46
+ ],
47
+ [
48
+ :province,
49
+ ' '
50
+ ],
51
+ :postal_code
52
+ ],
53
+ [
54
+ ', ',
55
+ :country
56
+ ]
57
+ ]
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,57 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/style'
3
+
4
+ describe Pinpoint::Format::Style do
5
+ let(:style_class) { Pinpoint::Format::Style }
6
+
7
+ it 'can instantiate itself based on a style definition' do
8
+ style_definition = '((%s, )(%l, ))(%p )%z(, %c)'
9
+ style = style_class.from_yaml style_definition
10
+
11
+ style.send(:structure).first.first.should eql [:street, ', ']
12
+ end
13
+
14
+ it 'can output an address based on a style' do
15
+ style_definition = '((%s, )(%l, ))(%p )%z(, %c)'
16
+ style = style_class.from_yaml style_definition
17
+ address = stub(street: 'a',
18
+ locality: 'b',
19
+ province: 'c',
20
+ postal_code: 'd',
21
+ country: 'e')
22
+
23
+ style.output(address).should eql 'a, b, c d, e'
24
+ end
25
+
26
+ it 'can output an address based on a style with newlines' do
27
+ style_definition = "((%s\n)((%l, ))(%p )%z\n)(%c\n)"
28
+ style = style_class.from_yaml style_definition
29
+ address = stub(street: 'a',
30
+ locality: 'b',
31
+ province: 'c',
32
+ postal_code: 'd',
33
+ country: 'e')
34
+
35
+ style.output(address).should eql <<-MULTILINE
36
+ a
37
+ b, c d
38
+ e
39
+ MULTILINE
40
+ end
41
+
42
+ it 'can safely output unsafe HTML' do
43
+ style_definition = "<span>%s</span>"
44
+ style = style_class.from_yaml style_definition
45
+ address = stub(:street => "<script>alert('Gotcha!');</script>")
46
+
47
+ style.output(address).should eql '<span>&lt;script&gt;alert(&#x27;Gotcha!&#x27;);&lt;/script&gt;</span>'
48
+ end
49
+
50
+ it 'understands not to output a grouping without alphanumeric characters' do
51
+ style_definition = '(%s, )'
52
+ style = style_class.from_yaml style_definition
53
+ address = stub(street: '')
54
+
55
+ style.output(address).should eql ''
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/token_list'
3
+
4
+ describe Pinpoint::Format::TokenList do
5
+ let(:token_list_class) { Pinpoint::Format::TokenList }
6
+ let(:token_list) { token_list_class.new }
7
+ let(:group_start_token) { stub(:type => :group_start) }
8
+ let(:group_end_token) { stub(:type => :group_end) }
9
+
10
+ it 'is an Array' do; token_list.should be_an Array; end
11
+
12
+ it 'is valid if the number of group pair tokens is equal' do
13
+ token_list = token_list_class.new [group_start_token, group_end_token]
14
+
15
+ token_list.should be_valid
16
+ end
17
+
18
+ it 'is not valid if the number of group pair tokens is unequal' do
19
+ token_list = token_list_class.new [group_start_token]
20
+
21
+ expect { token_list.valid? }.to raise_error Pinpoint::Format::UnevenNestingError
22
+ end
23
+
24
+ it 'yields each token to the block when processing' do
25
+ result = ''
26
+ token_list = token_list_class.new [group_start_token, group_end_token]
27
+
28
+ token_list.process_each! do |token|
29
+ result << token.type.to_s
30
+ end
31
+
32
+ result.should eql 'group_startgroup_end'
33
+ end
34
+
35
+ it 'deletes itself as it processes' do
36
+ token_list = token_list_class.new [group_start_token]
37
+
38
+ token_list.process_each! do |token|
39
+ end
40
+
41
+ token_list.should be_empty
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/token'
3
+
4
+ describe Pinpoint::Format::Token do
5
+ it 'can be instantiated with the proper arguments' do
6
+ token = Pinpoint::Format::Token.new(:foo, 'bar')
7
+
8
+ token.type.should eql :foo
9
+ token.value.should eql 'bar'
10
+ end
11
+
12
+ it 'always has a symbol for a type even if instantiated with something else' do
13
+ token = Pinpoint::Format::Token.new('foo', 'bar')
14
+
15
+ token.type.should eql :foo
16
+ token.value.should eql 'bar'
17
+ end
18
+
19
+ it 'can determine the value that is needed when processing the token' do
20
+ Pinpoint::Format::Token.new(:group_start).processed_value.should eql :group_start
21
+ Pinpoint::Format::Token.new(:group_end).processed_value.should eql :group_end
22
+ Pinpoint::Format::Token.new(:literal, 'foo').processed_value.should eql 'foo'
23
+ Pinpoint::Format::Token.new(:street).processed_value.should eql :street
24
+ end
25
+ end
@@ -0,0 +1,78 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format/tokenizer'
3
+
4
+ describe Pinpoint::Format::Tokenizer do
5
+ let(:tokenizer_class) { Pinpoint::Format::Tokenizer }
6
+ let(:tokenable) { '((%s), )(((%p) )(%z))(, (%c))' }
7
+ let(:tokenizer) { Pinpoint::Format::Tokenizer.new(tokenable) }
8
+
9
+ it 'can process a String into Tokens' do
10
+ tokenizer.to_token_list.map(&:to_ary).should eql [
11
+ [:group_start, '(' ],
12
+ [:group_start, '(' ],
13
+ [:street, '%s' ],
14
+ [:group_end, ')' ],
15
+ [:literal, ', ' ],
16
+ [:group_end, ')' ],
17
+ [:group_start, '(' ],
18
+ [:group_start, '(' ],
19
+ [:group_start, '(' ],
20
+ [:province, '%p' ],
21
+ [:group_end, ')' ],
22
+ [:literal, ' ' ],
23
+ [:group_end, ')' ],
24
+ [:group_start, '(' ],
25
+ [:postal_code, '%z' ],
26
+ [:group_end, ')' ],
27
+ [:group_end, ')' ],
28
+ [:group_start, '(' ],
29
+ [:literal, ', ' ],
30
+ [:group_start, '(' ],
31
+ [:country, '%c' ],
32
+ [:group_end, ')' ],
33
+ [:group_end, ')' ]
34
+ ]
35
+ end
36
+
37
+ context 'when the String passed contains literal percent sign tokens' do
38
+ let(:tokenable) { '%%%c' }
39
+
40
+ it 'parses correctly' do
41
+ tokenizer.to_token_list.map(&:to_ary).should eql [
42
+ [:literal, '%' ],
43
+ [:country, '%c' ]
44
+ ]
45
+ end
46
+ end
47
+
48
+ context 'when the String passed contains an improper syntax' do
49
+ let(:tokenable) { '%%%c%io' }
50
+
51
+ it 'parses correctly' do
52
+ expect { tokenizer.to_token_list }.to raise_error(
53
+ Pinpoint::Format::ParseError,
54
+ "Cannot parse the remainder of the tokenable string: '%io'"
55
+ )
56
+ end
57
+ end
58
+
59
+ context 'when the String passed contains complex grouping and parenthesis literals' do
60
+ let(:tokenable) { '%)%((%((%))%)%%%))' }
61
+
62
+ it 'parses correctly' do
63
+ tokenizer.to_token_list.map(&:to_ary).should eql [
64
+ [:literal, ')' ],
65
+ [:literal, '(' ],
66
+ [:group_start, '(' ],
67
+ [:literal, '(' ],
68
+ [:group_start, '(' ],
69
+ [:literal, ')' ],
70
+ [:group_end, ')' ],
71
+ [:literal, ')' ],
72
+ [:literal, '%' ],
73
+ [:literal, ')' ],
74
+ [:group_end, ')' ]
75
+ ]
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ require 'rspectacular'
2
+ require 'pinpoint/format'
3
+
4
+ describe Pinpoint::Format do
5
+ let(:format_class) { Pinpoint::Format }
6
+ let(:format) { format_class.new }
7
+
8
+ it 'can lookup a format by country' do
9
+ Pinpoint::Format::File.should_receive(:styles_for)
10
+ .and_return 'styles'
11
+
12
+ format = format_class.lookup_by_country(:us)
13
+
14
+ format.should be_a format_class
15
+ format.styles.should eql 'styles'
16
+ end
17
+
18
+ context 'when it has one or more Styles' do
19
+ let(:style) { stub }
20
+
21
+ before { format.styles = { :one_line => style } }
22
+
23
+ it 'tells the relevant Style to output the address' do
24
+ style.should_receive(:output).with('address').and_return 'formatted_address'
25
+
26
+ format.output('address', :style => :one_line).should eql 'formatted_address'
27
+ end
28
+
29
+ it 'defaults output style to one-line' do
30
+ style.should_receive(:output).with('address').and_return 'formatted_address'
31
+
32
+ format.output('address').should eql 'formatted_address'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,112 @@
1
+ require 'rspectacular'
2
+ require 'ostruct'
3
+ require 'pinpoint/formatter'
4
+
5
+
6
+ class Address < Struct.new( :name,
7
+ :street,
8
+ :locality,
9
+ :province,
10
+ :county,
11
+ :postal_code,
12
+ :country,
13
+ :latitude,
14
+ :longitude)
15
+ end
16
+
17
+ describe Pinpoint::Formatter do
18
+ let(:address) { Address.new 'Kwik-E-Mart',
19
+ '123 Apu Lane',
20
+ 'Springfield',
21
+ 'NW',
22
+ 'Springfield County',
23
+ '12345',
24
+ 'United States',
25
+ '12345',
26
+ '67890' }
27
+
28
+ describe '#format' do
29
+ it 'can format it in one line US format' do
30
+ expected = "Kwik-E-Mart, 123 Apu Lane, Springfield, NW 12345, United States"
31
+
32
+ Pinpoint::Formatter.format(address, country: :us,
33
+ style: :one_line_with_name)
34
+ .should eql(expected)
35
+ end
36
+
37
+ it 'can format it in multiline US format' do
38
+ expected = <<-MULTILINE
39
+ Kwik-E-Mart
40
+ 123 Apu Lane
41
+ Springfield, NW 12345
42
+ United States
43
+ MULTILINE
44
+
45
+ Pinpoint::Formatter.format(address, country: :us,
46
+ style: :multi_line_with_name)
47
+ .should eql(expected)
48
+ end
49
+
50
+ it 'can format it in HTML in US format' do
51
+ expected = <<-MULTILINE
52
+ <address>
53
+ <span class="section">
54
+ <span class="name">Kwik-E-Mart</span>
55
+ </span>
56
+ <span class="section">
57
+ <span class="street">123 Apu Lane</span>
58
+ </span>
59
+ <span class="section">
60
+ <span class="locality">Springfield</span>
61
+ <span class="province">NW</span>
62
+ <span class="postal_code">12345</span>
63
+ </span>
64
+ <span class="section">
65
+ <span class="country">United States</span>
66
+ </span>
67
+ </address>
68
+ MULTILINE
69
+
70
+ Pinpoint::Formatter.format(address, country: :us,
71
+ style: :html)
72
+ .should eql(expected)
73
+ end
74
+
75
+ context 'when the address contains unsafe characters' do
76
+ let(:address) { Address.new "<script>alert('Gotcha!');</script>",
77
+ '123 Apu Lane',
78
+ 'Springfield',
79
+ 'NW',
80
+ 'Springfield County',
81
+ '12345',
82
+ 'United States',
83
+ '12345',
84
+ '67890' }
85
+
86
+ it 'escapes anything that is unsafe' do
87
+ expected = <<-MULTILINE
88
+ <address>
89
+ <span class="section">
90
+ <span class="name">&lt;script&gt;alert(&#x27;Gotcha!&#x27;);&lt;/script&gt;</span>
91
+ </span>
92
+ <span class="section">
93
+ <span class="street">123 Apu Lane</span>
94
+ </span>
95
+ <span class="section">
96
+ <span class="locality">Springfield</span>
97
+ <span class="province">NW</span>
98
+ <span class="postal_code">12345</span>
99
+ </span>
100
+ <span class="section">
101
+ <span class="country">United States</span>
102
+ </span>
103
+ </address>
104
+ MULTILINE
105
+
106
+ Pinpoint::Formatter.format(address, country: :us,
107
+ style: :html)
108
+ .should eql(expected)
109
+ end
110
+ end
111
+ end
112
+ end