pg-hstore 1.1.3 → 1.1.4

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