altsv 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6dabb0913e3f6ee313714b955983a1b52a6ca3dfd3a567287cb08397184a8ffa
4
+ data.tar.gz: '090396592332217d2c087c8e8944b1b5cad271a08f5f2231de01b41002fc1422'
5
+ SHA512:
6
+ metadata.gz: a799aae3dd58843d7b7e70ebfdc5f48099e850fbff88d92e003e9615a1d9e86597ea9da95703ccc1377264bea9a3a5790bfb521761640e0b5d40775318d89175
7
+ data.tar.gz: 0516ea9c4d4b019309c7dca87a3016856bfe6e760d937a67b17b3382c61f34aae0d1e9aacd7a7d960ea14db63029cad4e1ec2e7d9dcc01d8b62471cacbaf2e65
@@ -0,0 +1,57 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ /.idea/
53
+
54
+ # Avoid the merging of the build intermediates
55
+ /target/
56
+
57
+ /lib/altsv/native.bundle
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.0
7
+ before_install: gem install bundler -v 1.17.2
@@ -0,0 +1,41 @@
1
+ [[package]]
2
+ name = "altsv"
3
+ version = "0.0.1"
4
+ dependencies = [
5
+ "helix 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
6
+ "libcruby-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
7
+ ]
8
+
9
+ [[package]]
10
+ name = "cstr-macro"
11
+ version = "0.1.0"
12
+ source = "registry+https://github.com/rust-lang/crates.io-index"
13
+
14
+ [[package]]
15
+ name = "helix"
16
+ version = "0.7.5"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ dependencies = [
19
+ "cstr-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
20
+ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
21
+ "libcruby-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
22
+ ]
23
+
24
+ [[package]]
25
+ name = "libc"
26
+ version = "0.2.48"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+
29
+ [[package]]
30
+ name = "libcruby-sys"
31
+ version = "0.7.5"
32
+ source = "registry+https://github.com/rust-lang/crates.io-index"
33
+ dependencies = [
34
+ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
35
+ ]
36
+
37
+ [metadata]
38
+ "checksum cstr-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db53fddba18cdd35477a7213a3ef6acfbfa333c31b42ce019e544c4a1420a06f"
39
+ "checksum helix 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49a017e3e798ad9386e0a0584e66fd6c04a80ccc1242eb8f689c62ce6f408240"
40
+ "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
41
+ "checksum libcruby-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fef6028cdce0c8d55676fd1d66bb810facef8cade0dd71d28511d375e84da4c0"
@@ -0,0 +1,11 @@
1
+ [package]
2
+ name = "altsv"
3
+ version = "0.0.1"
4
+ edition = "2018"
5
+
6
+ [lib]
7
+ crate-type = ["cdylib"]
8
+
9
+ [dependencies]
10
+ helix = "0.7.5"
11
+ libcruby-sys = "0.7.5"
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in altsv.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 condor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,78 @@
1
+ # altsv
2
+
3
+ An ALTernative LTSV Parser / Dumper gem partially written in Rust.
4
+
5
+ ## Prerequisites
6
+
7
+ * rustc (tested with 1.32.0)
8
+ * cargo (The de-fact standard package manager for Rust)
9
+
10
+ You can install both with [rustup.rs](https://rustup.rs/)
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'altsv'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install altsv
27
+
28
+ ## Usage
29
+
30
+ At first, you should require altsv:
31
+
32
+ require 'altsv'
33
+
34
+ In addition, if you manage gems with bundler, you should add the statement below into your Gemfile:
35
+
36
+ gem 'altsv'
37
+
38
+
39
+ ### parsing LTSV
40
+
41
+ # parse string
42
+ string = "label1:value1\tlabel2:value2"
43
+ values = Altsv.parse(string) # => [{:label1 => "value1", :label2 => "value2"}]
44
+
45
+ # parse via stream
46
+ # content: as below
47
+ # label1_1:value1_1\tlabel1_2:value1_2
48
+ # label2_1:value2_1\tlabel2_2:value2_2
49
+ stream = File.open("some_file.ltsv", "r")
50
+ values = Altsv.parse(stream)
51
+ # => [{:label1_1 => "value1_2", :label1_2 => "value1_2"},
52
+ # {:label2_1 => "value2_2", :label2_2 => "value2_2"}]
53
+
54
+ ### loading LTSV file
55
+
56
+ # load via path
57
+ values = Altsv.load("some_path.ltsv")
58
+
59
+ # load via stream
60
+ stream = File.open("some_file.ltsv", "r")
61
+ values = Altsv.load(stream) # => same as LTSV.parse(stream)
62
+
63
+ ### dumping into LTSV
64
+
65
+ value = {label1: "value1", label2: "value2"}
66
+ dumped = Altsv.dump(value) # => "label1:value1\tlabel2:value2"
67
+
68
+ Dumped objects should respond to :to_hash.
69
+
70
+ ## Development
71
+
72
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
73
+
74
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
75
+
76
+ ## Contributing
77
+
78
+ Bug reports and pull requests are welcome on GitHub at https://github.com/condor/altsv.
@@ -0,0 +1,5 @@
1
+ require 'helix_runtime/build_task'
2
+
3
+ HelixRuntime::BuildTask.new
4
+
5
+ require "bundler/gem_tasks"
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "altsv/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "altsv"
9
+ spec.version = Altsv::VERSION
10
+ spec.authors = ["condor"]
11
+ spec.email = ["condor1226@gmail.com"]
12
+
13
+ spec.summary = %q{an ALTernative ltSV parser / dumper library}
14
+ spec.description = %q{A more lightweight LTSV handler library partially written in Rust.}
15
+ spec.homepage = "https://github.com/condor/altsv"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = "https://github.com/condor/altsv"
22
+ spec.metadata["changelog_uri"] = "https://github.com/condor/altsv/blob/master/CHANGELOG.md"
23
+ else
24
+ raise "RubyGems 2.0 or newer is required to protect against " \
25
+ "public gem pushes."
26
+ end
27
+
28
+ # Specify which files should be added to the gem when it is released.
29
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+ spec.extensions = %w(ext/altsv/extconf.rb)
37
+
38
+ spec.add_dependency 'helix_runtime', '~> 0.7.5'
39
+
40
+ spec.add_development_dependency 'pry'
41
+ spec.add_development_dependency "bundler", "~> 1.17"
42
+ spec.add_development_dependency "rake", "~> 10.0"
43
+ spec.add_development_dependency "rspec", "~> 3.8", '< 4.0'
44
+ spec.add_development_dependency 'ltsv'
45
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "altsv"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ RAKEFILE = 'native.rake'
2
+
3
+ def command_exists(command, *extra_test_arguments)
4
+ raise "Command #{command} not found. exitting..." unless system(command, *extra_test_arguments)
5
+ end
6
+
7
+ command_exists('cargo', '--version')
8
+ command_exists('rustc', '--version')
9
+
10
+ File.open('Makefile', 'w') do |makefile|
11
+ makefile.puts <<~MAKEFILE
12
+ clean:
13
+ \trake -f #{RAKEFILE} clobber
14
+ install:
15
+ \trake -f #{RAKEFILE} build
16
+ MAKEFILE
17
+ end
18
+
19
+ File.open(RAKEFILE, 'w') do |rakefile|
20
+ rakefile.puts <<~RUBY
21
+ require 'helix_runtime/build_task'
22
+
23
+ HelixRuntime::BuildTask.new
24
+ RUBY
25
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ require 'helix_runtime'
3
+ require 'altsv/native'
4
+
5
+ require "altsv/version"
6
+
7
+ class Altsv
8
+ class Error < StandardError; end
9
+ # Your code goes here...
10
+
11
+ class << self
12
+ def parse(input)
13
+ case input
14
+ when String
15
+ parse_native input
16
+ when StringIO
17
+ parse_native input.string
18
+ when IO
19
+ input.each_line.map{|line| parse_line_native line}
20
+ end
21
+ end
22
+
23
+ def load(path_or_io)
24
+ case path_or_io
25
+ when String
26
+ File.open(path_or_io){|f| parse f}
27
+ when IO
28
+ parse(path_or_io)
29
+ else
30
+ raise ArgumentError, "#{name}.#{__method__} only accepts IO or path."
31
+ end
32
+ end
33
+
34
+ def dump(value)
35
+ dump_native value
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ class Altsv
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,356 @@
1
+ use std::collections::HashMap;
2
+ use std::ffi::CString;
3
+
4
+ use libcruby_sys::*;
5
+
6
+ use helix::*;
7
+
8
+ const BUFFER_SIZE_KEY: usize = 64usize;
9
+ const BUFFER_SIZE_VALUE: usize = 128usize;
10
+
11
+ struct HashMapWrapper {
12
+ map: HashMap<Symbol, Option<CString>>,
13
+ }
14
+
15
+ impl HashMapWrapper {
16
+ fn with_capacity(capacity: usize) -> Self {
17
+ HashMapWrapper {
18
+ map: HashMap::with_capacity(capacity)
19
+ }
20
+ }
21
+
22
+ fn insert(&mut self, key: &String, value: &str) {
23
+ let value_to_insert: Option<CString>;
24
+ if value.is_empty() {
25
+ value_to_insert = None;
26
+ } else {
27
+ value_to_insert = Some(CString::new(value).expect("This must success since it is from String"))
28
+ }
29
+ let key_to_insert = Symbol::from_string(key.clone());
30
+
31
+ self.map.insert(key_to_insert, value_to_insert);
32
+ }
33
+
34
+ fn inner(self) -> HashMap<Symbol, Option<CString>> {
35
+ self.map
36
+ }
37
+ }
38
+
39
+ impl ToRuby for HashMapWrapper {
40
+ fn to_ruby(self) -> ToRubyResult {
41
+ let hash: VALUE;
42
+ unsafe {
43
+ hash = rb_hash_new();
44
+
45
+ for (key, value) in self.inner().into_iter() {
46
+ let key_ruby = key.to_ruby().expect("This must success since it is from String");
47
+ let value_ruby = match value {
48
+ None => Qnil,
49
+ Some(v) => rb_utf8_str_new(v.as_ptr(), v.as_bytes().len() as i64),
50
+ };
51
+ rb_hash_aset(hash, key_ruby, value_ruby);
52
+ }
53
+ }
54
+
55
+ return Ok(hash);
56
+ }
57
+ }
58
+
59
+ fn parse_line(input: &str) -> HashMapWrapper {
60
+ let mut key = String::with_capacity(BUFFER_SIZE_KEY);
61
+ let mut value = String::with_capacity(BUFFER_SIZE_VALUE);
62
+ let mut in_value = false;
63
+ let mut escaping = false;
64
+
65
+ // First: count the key-value pairs.
66
+ let mut count = 0usize;
67
+ let mut chars = input.chars();
68
+ loop {
69
+ match chars.next() {
70
+ None => break,
71
+ Some(c) => {
72
+ match c {
73
+ '\t' => count += 1,
74
+ _ => {}
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ let mut line= HashMapWrapper::with_capacity(count);
81
+
82
+ // start actual parsing
83
+ let mut chars = input.chars();
84
+ loop {
85
+ match chars.next() {
86
+ None => {
87
+ if !key.is_empty() {
88
+ line.insert(&key, &value);
89
+ }
90
+ break;
91
+ }
92
+ Some(c) => {
93
+ if c == '\r' || c == '\n' {
94
+ if !key.is_empty() {
95
+ line.insert(&key, &value);
96
+ }
97
+ break;
98
+ }
99
+
100
+ let current_char: char;
101
+ if escaping {
102
+ match c {
103
+ 'n' => current_char = '\n',
104
+ 'r' => current_char = '\r',
105
+ 't' => current_char = '\t',
106
+ '\\' => current_char = '\\',
107
+ _ => {
108
+ current_char = c;
109
+ if in_value {
110
+ value.push('\\')
111
+ }else {
112
+ key.push('\\')
113
+ }
114
+ },
115
+ }
116
+ escaping = false;
117
+ } else {
118
+ match c {
119
+ '\\' => {
120
+ escaping = true;
121
+ continue;
122
+ },
123
+ ':' => {
124
+ // key-value separator(only when not separated)
125
+ if !in_value {
126
+ in_value = true;
127
+ continue;
128
+ }
129
+ }
130
+ '\t' => {
131
+ // field separator
132
+ if !key.is_empty() {
133
+ // TODO: Whether OR NOT the empty label should cause error?
134
+ line.insert(&key, &value);
135
+ }
136
+ key.clear();
137
+ value.clear();
138
+ in_value = false;
139
+ continue;
140
+ }
141
+ _ => {}
142
+ }
143
+ current_char = c;
144
+ }
145
+
146
+ if in_value {
147
+ value.push(current_char)
148
+ } else {
149
+ key.push(current_char)
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ line
156
+ }
157
+
158
+ const METHOD_NAME_RESPOND_TO: &[u8] = b"respond_to?\0`";
159
+ const METHOD_NAME_TO_H: &[u8] = b"to_h\0";
160
+ const METHOD_NAME_TO_HASH: &[u8] = b"to_hash\0";
161
+ const METHOD_NAME_TO_S: &[u8] = b"to_s\0";
162
+
163
+ const CLASS_NAME_ARGUMENT_ERROR: &str = "ArgumentError";
164
+
165
+ const MESSAGE_DUMP_ERROR: &'static str = "Argument does not respond to neither :to_h nor :to_hash";
166
+
167
+ unsafe fn rb_intern_u8(method_name: &[u8]) -> ID {
168
+ use std::mem;
169
+ rb_intern(mem::transmute::<&u8, c_string>(&method_name[0]))
170
+ }
171
+
172
+ unsafe fn respond_to(object: VALUE, name: ID) -> bool {
173
+ let respond_to = rb_intern_u8(METHOD_NAME_RESPOND_TO);
174
+ let method = rb_id2sym(name);
175
+
176
+ rb_funcall(object, respond_to, 1, method) == Qtrue
177
+ }
178
+
179
+ extern "C" fn join_hash(key: VALUE, value: VALUE, farg: *mut void) -> st_retval {
180
+ use std::mem;
181
+
182
+ let s = unsafe {mem::transmute::<*mut void, *mut DumpResult>(farg) };
183
+
184
+ match unsafe{ (*s).push_value(key, true) } {
185
+ None => {}
186
+ Some(error) => {
187
+ unsafe{ (*s).set_error(error) };
188
+ return st_retval::ST_STOP;
189
+ }
190
+ }
191
+
192
+ unsafe { (*s).push_char(':') };
193
+
194
+ match unsafe{ (*s).push_value(value, false) } {
195
+ None => {}
196
+ Some(error) => {
197
+ unsafe{ (*s).set_error(error) };
198
+ return st_retval::ST_STOP;
199
+ }
200
+ }
201
+ unsafe { (*s).push_char('\t') };
202
+
203
+ st_retval::ST_CONTINUE
204
+ }
205
+
206
+ struct DumpResult {
207
+ error: Option<Error>,
208
+ buffer: String,
209
+ }
210
+
211
+ impl DumpResult {
212
+ fn new(item_count: usize) -> Self{
213
+ DumpResult {
214
+ buffer: String::with_capacity(item_count * (BUFFER_SIZE_KEY + BUFFER_SIZE_VALUE)),
215
+ error: None,
216
+ }
217
+ }
218
+ fn push_value(&mut self, v: VALUE, for_key: bool) -> Option<Error>{
219
+ match unsafe {
220
+ if RB_TYPE_P(v, T_SYMBOL) {
221
+ String::from_ruby(rb_id2str(rb_sym2id(v)))
222
+ } else if RB_TYPE_P(v, T_STRING) {
223
+ String::from_ruby(v)
224
+ } else {
225
+ let to_s = rb_intern_u8(&METHOD_NAME_TO_S);
226
+ String::from_ruby(rb_funcall(v, to_s, 0))
227
+ }
228
+ } {
229
+ Ok(checked) => {
230
+ use helix::Error;
231
+
232
+ for c in String::from_checked(checked).chars() {
233
+ match c {
234
+ '\r' => self.buffer.push_str("\\r"),
235
+ '\n' => self.buffer.push_str("\\n"),
236
+ '\t' => self.buffer.push_str("\\t"),
237
+ ':' => {
238
+ if for_key {
239
+ return Some(Error::with_c_string(CString::new("Key should not include ':'").unwrap().as_ptr()));
240
+ }
241
+ self.buffer.push(c)
242
+ },
243
+ _ => self.buffer.push(c),
244
+ }
245
+ }
246
+ None
247
+ },
248
+ Err(e) => Some(e),
249
+ }
250
+ }
251
+
252
+ fn push_char(&mut self, c: char) {
253
+ self.buffer.push(c);
254
+ }
255
+
256
+ fn set_error(&mut self, e: Error) {
257
+ self.error = Some(e);
258
+ }
259
+
260
+ fn extract(self) -> Result<String, Error> {
261
+ match self.error {
262
+ Some(e) => Err(e),
263
+ None => Ok(String::from(self.buffer.trim_end())),
264
+ }
265
+ }
266
+ }
267
+
268
+ struct DumpArgument {
269
+ inner: VALUE,
270
+ count: usize,
271
+ }
272
+
273
+ impl DumpArgument {
274
+ pub unsafe fn from_hash(inner: VALUE) -> Self{
275
+ let count = RHASH_SIZE(inner) as usize;
276
+
277
+ DumpArgument{
278
+ inner,
279
+ count,
280
+ }
281
+ }
282
+ pub fn dump(&self) -> Result<String, Error> {
283
+ use std::mem;
284
+
285
+ let mut dump_result = DumpResult::new(self.count);
286
+ unsafe{
287
+ rb_hash_foreach(
288
+ self.inner,
289
+ join_hash,
290
+ mem::transmute::<&mut DumpResult, *mut void>(&mut dump_result)
291
+ )
292
+ };
293
+
294
+ dump_result.extract()
295
+ }
296
+ }
297
+
298
+ impl FromRuby for DumpArgument {
299
+ type Checked = CheckedValue<DumpArgument>;
300
+
301
+ fn from_ruby(value: VALUE) -> CheckResult<CheckedValue<DumpArgument>> {
302
+ unsafe {
303
+ if RB_TYPE_P(value, T_HASH) {
304
+ return Ok(CheckedValue::new(value));
305
+ }
306
+
307
+ let hashed_value: VALUE;
308
+ let to_h = rb_intern_u8(METHOD_NAME_TO_H);
309
+ if respond_to(value, to_h) {
310
+ hashed_value = rb_funcall(value, to_h, 0);
311
+ return Ok(CheckedValue::new(hashed_value));
312
+ }
313
+
314
+ let hashed_value: VALUE;
315
+ let to_h = rb_intern_u8(METHOD_NAME_TO_HASH);
316
+ if respond_to(value, to_h) {
317
+ hashed_value = rb_funcall(value, to_h, 0);
318
+ return Ok(CheckedValue::new(hashed_value));
319
+ }
320
+ }
321
+
322
+ let argument_error = unsafe {
323
+ let id_argument_error = rb_intern(CString::new(CLASS_NAME_ARGUMENT_ERROR).unwrap().as_ptr());
324
+ rb_const_get(rb_cObject, id_argument_error)
325
+ };
326
+ let argument_error_class = unsafe{ Class::from_value(argument_error) };
327
+ raise!(argument_error_class, MESSAGE_DUMP_ERROR);
328
+ }
329
+
330
+ fn from_checked(checked: CheckedValue<DumpArgument>) -> DumpArgument {
331
+ unsafe{ DumpArgument::from_hash(checked.to_value())}
332
+ }
333
+ }
334
+
335
+ ruby! {
336
+ class Altsv {
337
+ def parse_native(input: String) -> Vec<HashMapWrapper> {
338
+ let mut hashes: Vec<HashMapWrapper> = Vec::new();
339
+ let mut lines = input.lines();
340
+ loop {
341
+ match lines.next() {
342
+ Some(line) => hashes.push(parse_line(line)),
343
+ None => break,
344
+ }
345
+ }
346
+ hashes
347
+ }
348
+ def parse_line_native(input: String) -> HashMapWrapper {
349
+ parse_line(&input)
350
+ }
351
+
352
+ def dump_native(value: DumpArgument) -> Result<String, Error> {
353
+ value.dump()
354
+ }
355
+ }
356
+ }
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: altsv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - condor
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: helix_runtime
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.17'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.17'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.8'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '4.0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '3.8'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '4.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: ltsv
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: A more lightweight LTSV handler library partially written in Rust.
104
+ email:
105
+ - condor1226@gmail.com
106
+ executables: []
107
+ extensions:
108
+ - ext/altsv/extconf.rb
109
+ extra_rdoc_files: []
110
+ files:
111
+ - ".gitignore"
112
+ - ".travis.yml"
113
+ - Cargo.lock
114
+ - Cargo.toml
115
+ - Gemfile
116
+ - LICENSE
117
+ - README.md
118
+ - Rakefile
119
+ - altsv.gemspec
120
+ - bin/console
121
+ - bin/setup
122
+ - ext/altsv/extconf.rb
123
+ - lib/altsv.rb
124
+ - lib/altsv/version.rb
125
+ - src/lib.rs
126
+ homepage: https://github.com/condor/altsv
127
+ licenses: []
128
+ metadata:
129
+ homepage_uri: https://github.com/condor/altsv
130
+ source_code_uri: https://github.com/condor/altsv
131
+ changelog_uri: https://github.com/condor/altsv/blob/master/CHANGELOG.md
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubygems_version: 3.0.3
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: an ALTernative ltSV parser / dumper library
151
+ test_files: []