pg_array_parser 0.0.1 → 0.0.2

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.
data/.gitignore CHANGED
@@ -16,3 +16,5 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  benchmark.rb
19
+ bin/*
20
+ .rbenv-version
@@ -2,6 +2,10 @@ rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ - jruby-18mode
6
+ - jruby-19mode
7
+ before_script:
8
+ - rake install
5
9
 
6
10
  notifications:
7
11
  email: false
@@ -0,0 +1,6 @@
1
+ # 0.0.2
2
+ * Refactored C extension - [jeremyevans](https://github.com/jeremyevens) - Merged at [ad4987](https://github.com/dockyard/pg_array_parser/commit/ad4987dba411decca4aebd0750c990212dc81039)
3
+ * Adds JRuby support - thanks to [tychobrailleur](https://github.com/tychobrailleur) for help with the java class
4
+
5
+ # 0.0.1
6
+ * Initial release
data/README.md CHANGED
@@ -18,9 +18,24 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- Include the `PgArrayParser` module. Call `PgArrayParser#parse_pg_array`
22
- method to return a multi-dimensional array of strings from a PostgreSQL
23
- array value
21
+ Include the `PgArrayParser` module, which provides the `parse_pg_array`
22
+ method.
23
+
24
+ ```ruby
25
+ class MyPostgresParser
26
+ include PgArrayParser
27
+ end
28
+
29
+ parser = MyPostgresParser.new
30
+ parser.parse_pg_array '{}'
31
+ # => []
32
+ parser.parse_pg_array '{1,2,3,4}'
33
+ # => ["1", "2", "3", "4"]
34
+ parser.parse_pg_array '{1,{2,3},4}'
35
+ # => ["1", ["2", "3"], "4"]
36
+ parser.parse_pg_array '{some,strings that,"May have some ,\'s"}'
37
+ # => ["some", "strings that", "May have some ,'s"]
38
+ ```
24
39
 
25
40
  ## Authors
26
41
 
data/Rakefile CHANGED
@@ -3,6 +3,13 @@ require 'bundler/gem_tasks'
3
3
 
4
4
  require 'rspec/core/rake_task'
5
5
 
6
+ spec = Gem::Specification.load('pg_array_parser.gemspec')
7
+
8
+ if RUBY_PLATFORM =~ /java/
9
+ require 'rake/javaextensiontask'
10
+ Rake::JavaExtensionTask.new('pg_array_parser', spec)
11
+ end
12
+
6
13
  task :spec => :install
7
14
 
8
15
  RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,113 @@
1
+ package pgarrayparser;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyArray;
5
+ import org.jruby.RubyClass;
6
+ import org.jruby.RubyFixnum;
7
+ import org.jruby.RubyString;
8
+ import org.jruby.RubyNil;
9
+ import org.jruby.RubyModule;
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.anno.JRubyMethod;
12
+ import org.jruby.anno.JRubyClass;
13
+ import org.jruby.runtime.ObjectAllocator;
14
+ import org.jruby.runtime.ThreadContext;
15
+ import org.jruby.runtime.builtin.IRubyObject;
16
+ import org.jruby.runtime.load.BasicLibraryService;
17
+
18
+ @JRubyClass(name = "PgArrayParser::PgArrayParserEngine")
19
+ public class PgArrayParserEngine extends RubyObject {
20
+ public PgArrayParserEngine(final Ruby runtime, RubyClass rubyClass) {
21
+ super(runtime, rubyClass);
22
+ }
23
+
24
+ private Ruby runtime;
25
+ private int index;
26
+ private String arrayString;
27
+ @JRubyMethod(name = "parse_pg_array")
28
+ public IRubyObject parse_pg_array(ThreadContext context, IRubyObject value) {
29
+ runtime = context.getRuntime();
30
+ index = 1;
31
+ arrayString = value.asJavaString();
32
+ IRubyObject returnValue = readArray();
33
+ return returnValue;
34
+
35
+ }
36
+
37
+ private RubyArray readArray()
38
+ {
39
+ RubyArray array = RubyArray.newArray(runtime, 1);
40
+
41
+ int openQuote = 0;
42
+ boolean escapeNext = false;
43
+ char currentChar;
44
+ StringBuilder word = new StringBuilder();
45
+
46
+ if(index < arrayString.length() && arrayString.charAt(index) == '}')
47
+ {
48
+ return array;
49
+ }
50
+
51
+ for(;index < arrayString.length(); ++index)
52
+ {
53
+ currentChar = arrayString.charAt(index);
54
+ if(openQuote < 1)
55
+ {
56
+ if(currentChar == ',' || currentChar == '}')
57
+ {
58
+ if(!escapeNext)
59
+ {
60
+ if(openQuote == 0 && word.length() == 4 && word.toString().equals("NULL"))
61
+ {
62
+ array.append(runtime.getNil());
63
+ }
64
+ else
65
+ {
66
+ array.append(RubyString.newString(runtime, word.toString()));
67
+ }
68
+ }
69
+ if(currentChar == '}')
70
+ {
71
+ return array;
72
+ }
73
+ escapeNext = false;
74
+ openQuote = 0;
75
+ word = new StringBuilder();
76
+ }
77
+ else if(currentChar == '"')
78
+ {
79
+ openQuote = 1;
80
+ }
81
+ else if(currentChar == '{')
82
+ {
83
+ index++;
84
+ array.append(readArray());
85
+ escapeNext = true;
86
+ }
87
+ else
88
+ {
89
+ word.append(String.valueOf(currentChar));
90
+ }
91
+ }
92
+ else if(escapeNext)
93
+ {
94
+ word.append(String.valueOf(currentChar));
95
+ escapeNext = false;
96
+ }
97
+ else if(currentChar == '\\')
98
+ {
99
+ escapeNext = true;
100
+ }
101
+ else if(currentChar == '"')
102
+ {
103
+ openQuote = -1;
104
+ }
105
+ else
106
+ {
107
+ word.append(String.valueOf(currentChar));
108
+ }
109
+ }
110
+
111
+ return array;
112
+ }
113
+ }
@@ -0,0 +1,32 @@
1
+ package pgarrayparser;
2
+
3
+ import java.lang.Long;
4
+ import java.io.IOException;
5
+
6
+ import org.jruby.Ruby;
7
+ import org.jruby.RubyArray;
8
+ import org.jruby.RubyClass;
9
+ import org.jruby.RubyFixnum;
10
+ import org.jruby.RubyModule;
11
+ import org.jruby.RubyObject;
12
+ import org.jruby.anno.JRubyMethod;
13
+ import org.jruby.runtime.ObjectAllocator;
14
+ import org.jruby.runtime.ThreadContext;
15
+ import org.jruby.runtime.builtin.IRubyObject;
16
+ import org.jruby.runtime.load.BasicLibraryService;
17
+
18
+ public class PgArrayParserEngineService implements BasicLibraryService {
19
+
20
+ public boolean basicLoad(Ruby runtime) throws IOException {
21
+
22
+ RubyModule pgArrayParser = runtime.defineModule("PgArrayParser");
23
+ RubyClass pgArrayParserEngine = pgArrayParser.defineClassUnder("PgArrayParserEngine", runtime.getObject(), new ObjectAllocator() {
24
+ public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
25
+ return new PgArrayParserEngine(runtime, rubyClass);
26
+ }
27
+ });
28
+
29
+ pgArrayParserEngine.defineAnnotatedMethods(PgArrayParserEngine.class);
30
+ return true;
31
+ }
32
+ }
@@ -1,90 +1,109 @@
1
1
  #include <ruby.h>
2
2
 
3
- VALUE PgArrayParser = Qnil;
4
-
5
- //Prototypes
6
- VALUE read_array(int *index, char *string, int *length, char *word);
7
- VALUE parse_pg_array(VALUE self, VALUE pg_array_string);
3
+ /* Prototype */
4
+ VALUE read_array(int *index, char *string, int length, char *word);
8
5
 
9
6
  VALUE parse_pg_array(VALUE self, VALUE pg_array_string) {
10
7
 
11
- //convert to c-string, create a buffer of the same length, as that will be the worst case
8
+ /* convert to c-string, create a buffer of the same length, as that will be the worst case */
12
9
  char *c_pg_array_string = StringValueCStr(pg_array_string);
13
10
  int array_string_length = RSTRING_LEN(pg_array_string);
14
- char *word = malloc(sizeof(char) * (array_string_length + 1));
11
+ char *word = malloc(array_string_length + 1);
15
12
 
16
13
  int index = 1;
17
14
 
18
- VALUE return_value = read_array(&index, c_pg_array_string, &array_string_length, word);
15
+ VALUE return_value = read_array(&index, c_pg_array_string, array_string_length, word);
19
16
  free(word);
20
17
  return return_value;
21
18
  }
22
19
 
23
- VALUE read_array(int *index, char *c_pg_array_string, int *array_string_length, char *word)
20
+ VALUE read_array(int *index, char *c_pg_array_string, int array_string_length, char *word)
24
21
  {
25
- // Return value: array
22
+ /* Return value: array */
26
23
  VALUE array;
27
- array = rb_ary_new();
28
24
  int word_index = 0;
25
+
26
+ /* The current character in the input string. */
27
+ char c;
28
+
29
+ /* 0: Currently outside a quoted string, current word never quoted
30
+ * 1: Currently inside a quoted string
31
+ * -1: Currently outside a quoted string, current word previously quoted */
29
32
  int openQuote = 0;
30
- for(;(*index) < (*array_string_length); ++(*index))
33
+
34
+ /* Inside quoted input means the next character should be treated literally,
35
+ * instead of being treated as a metacharacter.
36
+ * Outside of quoted input, means that the word shouldn't be pushed to the array,
37
+ * used when the last entry was a subarray (which adds to the array itself). */
38
+ int escapeNext = 0;
39
+
40
+ array = rb_ary_new();
41
+
42
+ /* Special case the empty array, so it doesn't need to be handled manually inside
43
+ * the loop. */
44
+ if(((*index) < array_string_length) && c_pg_array_string[(*index)] == '}')
45
+ {
46
+ return array;
47
+ }
48
+
49
+ for(;(*index) < array_string_length; ++(*index))
31
50
  {
32
- if(!openQuote && (c_pg_array_string[*index] == ','))
51
+ c = c_pg_array_string[*index];
52
+ if(openQuote < 1)
33
53
  {
34
- if(c_pg_array_string[(*index) - 1] != '"' && c_pg_array_string[(*index) - 1] != '}')
54
+ if(c == ',' || c == '}')
35
55
  {
36
- word[word_index] = '\0';
37
- if (word_index == 4 && !strcmp(word,"NULL"))
56
+ if(!escapeNext)
38
57
  {
39
- rb_ary_push(array, Qnil);
58
+ if(openQuote == 0 && word_index == 4 && !strncmp(word, "NULL", word_index))
59
+ {
60
+ rb_ary_push(array, Qnil);
61
+ }
62
+ else
63
+ {
64
+ rb_ary_push(array, rb_str_new(word, word_index));
65
+ }
40
66
  }
41
- else
67
+ if(c == '}')
42
68
  {
43
- rb_ary_push(array, rb_str_new2(word));
69
+ return array;
44
70
  }
71
+ escapeNext = 0;
72
+ openQuote = 0;
45
73
  word_index = 0;
46
74
  }
47
- }
48
- else if(!openQuote && c_pg_array_string[*index] == '}')
49
- {
50
- if(word_index > 0 && c_pg_array_string[(*index) - 1] != '"')
75
+ else if(c == '"')
51
76
  {
52
- word[word_index] = '\0';
53
- if (word_index == 4 && !strcmp(word,"NULL"))
54
- {
55
- rb_ary_push(array, Qnil);
56
- }
57
- else
58
- {
59
- rb_ary_push(array, rb_str_new2(word));
60
- }
61
- word_index = 0;
77
+ openQuote = 1;
78
+ }
79
+ else if(c == '{')
80
+ {
81
+ (*index)++;
82
+ rb_ary_push(array, read_array(index, c_pg_array_string, array_string_length, word));
83
+ escapeNext = 1;
84
+ }
85
+ else
86
+ {
87
+ word[word_index] = c;
88
+ word_index++;
62
89
  }
63
- return array;
64
- }
65
- else if (openQuote && c_pg_array_string[*index] == '"' && c_pg_array_string[(*index) - 1] == '\\')
66
- {
67
- word[word_index - 1] = '"';
68
90
  }
69
- else if (openQuote && c_pg_array_string[*index] == '"' && c_pg_array_string[(*index) - 1] != '\\')
70
- {
71
- word[word_index] = '\0';
72
- word_index = 0;
73
- openQuote = 0;
74
- rb_ary_push(array, rb_str_new2(word));
91
+ else if (escapeNext) {
92
+ word[word_index] = c;
93
+ word_index++;
94
+ escapeNext = 0;
75
95
  }
76
- else if(c_pg_array_string[*index] == '"')
96
+ else if (c == '\\')
77
97
  {
78
- openQuote = 1;
98
+ escapeNext = 1;
79
99
  }
80
- else if(!openQuote && c_pg_array_string[*index] == '{')
100
+ else if (c == '"')
81
101
  {
82
- (*index)++;
83
- rb_ary_push(array, read_array(index, c_pg_array_string, array_string_length, word));
102
+ openQuote = -1;
84
103
  }
85
104
  else
86
105
  {
87
- word[word_index] = c_pg_array_string[*index];
106
+ word[word_index] = c;
88
107
  word_index++;
89
108
  }
90
109
  }
@@ -93,9 +112,6 @@ VALUE read_array(int *index, char *c_pg_array_string, int *array_string_length,
93
112
  }
94
113
 
95
114
  void Init_pg_array_parser(void) {
96
- PgArrayParser = rb_define_module("PgArrayParser");
97
- rb_define_method(PgArrayParser, "parse_pg_array", parse_pg_array, 1);
98
-
115
+ rb_define_method(rb_define_module("PgArrayParser"), "parse_pg_array", parse_pg_array, 1);
99
116
  }
100
117
 
101
-
Binary file
@@ -1,2 +1,18 @@
1
- require "pg_array_parser/version"
2
- require 'pg_array_parser/pg_array_parser'
1
+ require File.expand_path('../pg_array_parser/version', __FILE__)
2
+ require File.expand_path('../pg_array_parser', __FILE__)
3
+
4
+ if RUBY_PLATFORM =~ /java/
5
+ module PgArrayParser
6
+ require 'jruby'
7
+ require File.expand_path('../pg_array_parser.jar', __FILE__)
8
+ require 'pgArrayParser/pg_array_parser_engine'
9
+
10
+ def parse_pg_array(value)
11
+ @parser ||= PgArrayParserEngine.new
12
+ @parser.parse_pg_array(value)
13
+ end
14
+ end
15
+ else
16
+ require 'pg_array_parser/pg_array_parser'
17
+ end
18
+
@@ -1,3 +1,3 @@
1
1
  module PgArrayParser
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
@@ -3,19 +3,24 @@ require File.expand_path('../lib/pg_array_parser/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Dan McClain"]
6
- gem.email = ["git@danseaver.com"]
6
+ gem.email = ["git@danmcclain.net"]
7
7
  gem.description = %q{Simple library to parse PostgreSQL arrays into a array of strings}
8
8
  gem.summary = %q{Converts PostgreSQL array strings into arrays of strings}
9
9
  gem.homepage = ""
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
12
12
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
- gem.extensions = ['ext/pg_array_parser/extconf.rb']
13
+ if RUBY_PLATFORM =~ /java/
14
+ gem.files << 'lib/pg_array_parser.jar'
15
+ else
16
+ gem.extensions = ['ext/pg_array_parser/extconf.rb']
17
+ end
14
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
19
  gem.name = "pg_array_parser"
16
20
  gem.require_paths = ["lib"]
17
21
  gem.version = PgArrayParser::VERSION
18
22
 
19
- gem.add_development_dependency 'rspec', '~> 2.10.0'
23
+ gem.add_development_dependency 'rspec', '~> 2.11.0'
20
24
  gem.add_development_dependency 'rake', '~> 0.9.2.2'
25
+ gem.add_development_dependency 'rake-compiler'
21
26
  end
@@ -9,6 +9,12 @@ describe 'PgArrayParser' do
9
9
 
10
10
  describe '#parse_pg_array' do
11
11
  context 'one dimensional arrays' do
12
+ context 'empty' do
13
+ it 'returns an empty array' do
14
+ parser.parse_pg_array(%[{}]).should eq []
15
+ end
16
+ end
17
+
12
18
  context 'no strings' do
13
19
  it 'returns an array of strings' do
14
20
  parser.parse_pg_array(%[{1,2,3}]).should eq ['1','2','3']
@@ -35,10 +41,21 @@ describe 'PgArrayParser' do
35
41
  it 'returns an array of strings when containing an escaped quote' do
36
42
  parser.parse_pg_array(%[{1,"2\\",3",4}]).should eq ['1','2",3','4']
37
43
  end
44
+
45
+ it 'returns an array of strings when containing an escaped backslash' do
46
+ parser.parse_pg_array(%[{1,"2\\\\",3,4}]).should eq ['1','2\\','3','4']
47
+ parser.parse_pg_array(%[{1,"2\\\\\\",3",4}]).should eq ['1','2\\",3','4']
48
+ end
38
49
  end
39
50
  end
40
51
 
41
52
  context 'two dimensional arrays' do
53
+ context 'empty' do
54
+ it 'returns an empty array' do
55
+ parser.parse_pg_array(%[{{}}]).should eq [[]]
56
+ parser.parse_pg_array(%[{{},{}}]).should eq [[],[]]
57
+ end
58
+ end
42
59
  context 'no strings' do
43
60
  it 'returns an array of strings with a sub array' do
44
61
  parser.parse_pg_array(%[{1,{2,3},4}]).should eq ['1',['2','3'],'4']
@@ -60,6 +77,12 @@ describe 'PgArrayParser' do
60
77
  end
61
78
  end
62
79
  context 'three dimensional arrays' do
80
+ context 'empty' do
81
+ it 'returns an empty array' do
82
+ parser.parse_pg_array(%[{{{}}}]).should eq [[[]]]
83
+ parser.parse_pg_array(%[{{{},{}},{{},{}}}]).should eq [[[],[]],[[],[]]]
84
+ end
85
+ end
63
86
  it 'returns an array of strings with sub arrays' do
64
87
  parser.parse_pg_array(%[{1,{2,{3,4}},{NULL,6},7}]).should eq ['1',['2',['3','4']],[nil,'6'],'7']
65
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_array_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-11 00:00:00.000000000 Z
12
+ date: 2012-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 2.10.0
21
+ version: 2.11.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 2.10.0
29
+ version: 2.11.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rake
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -43,9 +43,25 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.9.2.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake-compiler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  description: Simple library to parse PostgreSQL arrays into a array of strings
47
63
  email:
48
- - git@danseaver.com
64
+ - git@danmcclain.net
49
65
  executables: []
50
66
  extensions:
51
67
  - ext/pg_array_parser/extconf.rb
@@ -53,13 +69,16 @@ extra_rdoc_files: []
53
69
  files:
54
70
  - .gitignore
55
71
  - .travis.yml
72
+ - CHANGELOG.md
56
73
  - Gemfile
57
74
  - LICENSE
58
75
  - README.md
59
76
  - Rakefile
77
+ - ext/pg_array_parser/PgArrayParserEngine.java
78
+ - ext/pg_array_parser/PgArrayParserEngineService.java
60
79
  - ext/pg_array_parser/extconf.rb
61
80
  - ext/pg_array_parser/pg_array_parser.c
62
- - lib/pg_array_parser.bundle
81
+ - lib/pg_array_parser.jar
63
82
  - lib/pg_array_parser.rb
64
83
  - lib/pg_array_parser/version.rb
65
84
  - pg_array_parser.gemspec
@@ -92,3 +111,4 @@ summary: Converts PostgreSQL array strings into arrays of strings
92
111
  test_files:
93
112
  - spec/parser_spec.rb
94
113
  - spec/spec_helper.rb
114
+ has_rdoc:
Binary file