pg-hstore 1.1.3 → 1.1.4

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.
Files changed (2) hide show
  1. data/lib/pg_hstore.rb +46 -59
  2. metadata +6 -5
@@ -1,94 +1,81 @@
1
- require 'strscan'
2
-
3
1
  module PgHstore
4
2
  SINGLE_QUOTE = "'"
5
3
  DOUBLE_QUOTE = '"'
6
4
 
7
- extend self
8
-
9
- def parse(string)
10
- hash = {}
11
-
12
- # remove single quotes around literal if necessary
13
- string = string[1..-2] if string[0] == SINGLE_QUOTE and string[-1] == SINGLE_QUOTE
14
-
15
- scanner = StringScanner.new(string)
16
- while !scanner.eos?
17
- k = parse_quotable_string(scanner)
18
- skip_key_value_delimiter(scanner)
19
- v = parse_quotable_string(scanner)
20
- skip_pair_delimiter(scanner)
21
- # controversial...
22
- # to_sym, or what?
23
- hash[k.to_sym] = v
5
+ QUOTED_LITERAL = /"[^"\\]*(?:\\.[^"\\]*)*"/
6
+ UNQUOTED_LITERAL = /[^\s=,][^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
7
+ LITERAL = /(#{QUOTED_LITERAL}|#{UNQUOTED_LITERAL})/
8
+ PAIR = /#{LITERAL}\s*=>\s*#{LITERAL}/
9
+ NULL = /\ANULL\z/i
10
+ # set symbolize_keys = false if you want string keys
11
+ # thanks to https://github.com/engageis/activerecord-postgres-hstore for regexps!
12
+ def PgHstore.load(hstore, symbolize_keys = true)
13
+ hstore = unquote hstore, SINGLE_QUOTE
14
+ hstore.scan(PAIR).inject({}) do |memo, (k, v)|
15
+ k = unescape unquote(k, DOUBLE_QUOTE)
16
+ k = k.to_sym if symbolize_keys
17
+ v = (v =~ NULL) ? nil : unescape(unquote(v, DOUBLE_QUOTE))
18
+ memo[k] = v
19
+ memo
24
20
  end
25
-
26
- hash
27
21
  end
28
22
 
29
23
  # set for_parameter = true if you're using the output for a bind variable
30
- def dump(hash, for_parameter = false)
31
- string = hash.map do |k, v|
24
+ def PgHstore.dump(hash, for_parameter = false)
25
+ memo = hash.map do |k, v|
32
26
  if v.nil?
33
- # represent nil as NULL without quotes
34
27
  v = "NULL"
35
28
  else
36
- v = double_quote_escape v
29
+ v = escape v
37
30
  unless for_parameter
38
- v = single_quote_escape v
31
+ v = escape_single_quotes v
39
32
  end
40
- # otherwise, write a double-quoted string with backslash escapes for quotes
41
33
  v = DOUBLE_QUOTE + v + DOUBLE_QUOTE
42
34
  end
43
- k = double_quote_escape k
35
+ k = escape k
44
36
  unless for_parameter
45
- k = single_quote_escape k
37
+ k = escape_single_quotes k
46
38
  end
47
39
  k = DOUBLE_QUOTE + k + DOUBLE_QUOTE
48
-
49
- # TODO: throw an error if there is a NULL key
50
40
  [k, v].join ' => '
51
- end.join(", ")
41
+ end.join(', ')
52
42
  if for_parameter
53
- string
43
+ memo
54
44
  else
55
- SINGLE_QUOTE + string + SINGLE_QUOTE
45
+ SINGLE_QUOTE + memo + SINGLE_QUOTE
56
46
  end
57
47
  end
58
48
 
59
- private
60
-
61
- def quoted_string(scanner)
62
- key = scanner.scan(/(\\"|[^"])*/)
63
- key = key.gsub(/\\(.)/, '\1')
64
- scanner.skip(/"/)
65
- key
49
+ class << self
50
+ # deprecated; use PgHstore.load
51
+ alias parse load
66
52
  end
67
-
68
- def parse_quotable_string(scanner)
69
- if scanner.scan(/"/)
70
- value = quoted_string(scanner)
53
+
54
+ private
55
+
56
+ def PgHstore.unquote(string, quote_char)
57
+ if string.start_with? quote_char
58
+ string[1..-2]
71
59
  else
72
- value = scanner.scan(/\w+/)
73
- value = nil if value == "NULL"
74
- # TODO: values but not keys may be NULL
60
+ string
75
61
  end
76
62
  end
77
63
 
78
- def skip_key_value_delimiter(scanner)
79
- scanner.skip(/\s*=>\s*/)
64
+ ESCAPED_CHAR = /\\(.)/
65
+ def PgHstore.unescape(literal)
66
+ literal.gsub(ESCAPED_CHAR, '\1').gsub ESCAPED_SINGLE_QUOTE, SINGLE_QUOTE
80
67
  end
81
-
82
- def skip_pair_delimiter(scanner)
83
- scanner.skip(/,\s*/)
84
- end
85
-
86
- def double_quote_escape(str)
87
- str.to_s.gsub DOUBLE_QUOTE, '\"'
68
+
69
+ NON_ESCAPE_SLASH = '\\'
70
+ ESCAPED_SLASH = '\\\\'
71
+ ESCAPED_DOUBLE_QUOTE = '\"'
72
+ def PgHstore.escape(string)
73
+ string.to_s.gsub(NON_ESCAPE_SLASH) {ESCAPED_SLASH}.gsub DOUBLE_QUOTE, ESCAPED_DOUBLE_QUOTE
88
74
  end
89
75
 
90
- def single_quote_escape(str)
91
- str.to_s.gsub(/\\(?!")/) {'\\\\'}.gsub(SINGLE_QUOTE, "''")
76
+ ESCAPED_SINGLE_QUOTE = "''"
77
+ def PgHstore.escape_single_quotes(literal)
78
+ literal.to_s.gsub SINGLE_QUOTE, ESCAPED_SINGLE_QUOTE
92
79
  end
93
80
 
94
81
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg-hstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-04 00:00:00.000000000 Z
13
+ date: 2013-02-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -28,7 +28,8 @@ dependencies:
28
28
  - - ~>
29
29
  - !ruby/object:Gem::Version
30
30
  version: 2.5.0
31
- description: postgresql hstore parser/deparser - provides PgHstore.dump and PgHstore.parse
31
+ description: postgresql hstore parser/deparser - provides PgHstore.dump and PgHstore.load
32
+ (aka parse)
32
33
  email:
33
34
  - pvh@heroku.com
34
35
  - seamus@abshere.net
@@ -57,9 +58,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
58
  version: '0'
58
59
  requirements: []
59
60
  rubyforge_project:
60
- rubygems_version: 1.8.24
61
+ rubygems_version: 1.8.25
61
62
  signing_key:
62
- specification_version: 2
63
+ specification_version: 3
63
64
  summary: ''
64
65
  test_files: []
65
66
  has_rdoc: