filedictrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 74171da9cf75b57d441faad6754c05e718a170fdada7618cd593ddcc8f8b982a
4
+ data.tar.gz: 6a88336c3e3cb8e1a18d50bc14bd49794f0ba10e614667c0a086dfb9cd35d11c
5
+ SHA512:
6
+ metadata.gz: 9dde01e9a2f1af933ec22e7648797fbbd393362bd9abdfc7ff351104aa0184f02222edcc8c59de98770172f4e1e9c7285d61e9d2b89d575a06aebacb080d86d3
7
+ data.tar.gz: d569f379a3787a42dcd691a28b57e68ba1dd5579c4afb8741aad66d6ff13d58d2dba5e949772684c41cbec4ecccc9b55de9e1b9506353c447a37d7fd04d14e65
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in filedictrb.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rake-compiler"
11
+
12
+ gem "rspec", "~> 3.0"
13
+
14
+ gem "rubocop", "~> 1.7"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Nigel Baillie
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Filedictrb
2
+
3
+ Ruby wrapper for [filedict](https://github.com/Resonious/filedict).
4
+
5
+ The idea is the provide an interface that behaves exactly like a `Hash<Set<String>>`, but the data is bound to a file. The file is memory-mapped, and so it is shared across processes, and updates are flushed automatically by the operating system.
6
+
7
+ As of writing, this gem is still brand new, not production-ready. I'm pretty sure you'll get a segfault if you use non-string keys or values.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'filedictrb'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install filedictrb
24
+
25
+ ## Usage
26
+
27
+ You can use `Filedict::Hash` almost just like a regular `Hash`.
28
+
29
+ ```ruby
30
+ dict = Filedict::Hash.new('path/to/data/file')
31
+ dict['key'].add 'value'
32
+
33
+ dict['key'] # should equal Filedict::Set['value']
34
+
35
+ # if another process comes along and appends 'value 2', then ...
36
+ dict['key'] # should equal Filedict::Set['value', 'value 2']
37
+ ```
38
+
39
+ ## Development
40
+
41
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
42
+
43
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/filedictrb.
48
+
49
+ ## License
50
+
51
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ require "rake/extensiontask"
13
+
14
+ task build: :compile
15
+
16
+ Rake::ExtensionTask.new("filedictrb") do |ext|
17
+ ext.lib_dir = "lib/filedictrb"
18
+ end
19
+
20
+ task default: %i[clobber compile spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "filedict"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ create_makefile("filedictrb/filedictrb")
@@ -0,0 +1,11 @@
1
+ #include "filedictrb.h"
2
+ #include "hash.h"
3
+
4
+ VALUE mFiledict;
5
+
6
+ void
7
+ Init_filedictrb(void)
8
+ {
9
+ mFiledict = rb_define_module("Filedict");
10
+ fdrb_init_hash();
11
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef FILEDICTRB_H
2
+ #define FILEDICTRB_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #define FILEDICT_IMPL 1
7
+ #include "../filedict/filedict.h"
8
+ #undef FILEDICT_IMPL
9
+
10
+ #endif /* FILEDICTRB_H */
@@ -0,0 +1,151 @@
1
+ #include "hash.h"
2
+ #include "../filedict/filedict.h"
3
+
4
+ extern VALUE mFiledict;
5
+ VALUE cHash;
6
+ VALUE mSetExt;
7
+ VALUE cSet;
8
+
9
+ ID id_add;
10
+ ID id_remove;
11
+ ID id_freeze;
12
+ ID id_fd_hash;
13
+ ID id_fd_key;
14
+
15
+ /*
16
+ * ==============================
17
+ * Custom allocation / GC support
18
+ * ==============================
19
+ *
20
+ * Used as a reference:
21
+ * https://github.com/ruby-prof/ruby-prof/blob/master/ext/ruby_prof/rp_profile.c
22
+ *
23
+ * This stuff is necessary in order for GC to work properly when we hold
24
+ * references to Ruby objects in C code.
25
+ */
26
+
27
+ static void fd_hash_mark(void *data) {
28
+ /* TODO: do we need to hold ruby objects? */
29
+ /* fd_hash_t *fd_hash = (fd_hash_t*)data; */
30
+ }
31
+
32
+ static void fd_hash_free(void *data) {
33
+ fd_hash_t *fd_hash = (fd_hash_t*)data;
34
+
35
+ filedict_deinit(&fd_hash->filedict);
36
+
37
+ xfree(fd_hash);
38
+ }
39
+
40
+ size_t fd_hash_size(const void* _data) {
41
+ return sizeof(fd_hash_t);
42
+ }
43
+
44
+ static const rb_data_type_t fd_hash_type =
45
+ {
46
+ .wrap_struct_name = "Filedict::Hash",
47
+ .function =
48
+ {
49
+ .dmark = fd_hash_mark,
50
+ .dfree = fd_hash_free,
51
+ .dsize = fd_hash_size,
52
+ },
53
+ .data = NULL,
54
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
55
+ };
56
+
57
+ static VALUE fd_hash_allocate(VALUE klass) {
58
+ VALUE result;
59
+ fd_hash_t* fd_hash;
60
+
61
+ result = TypedData_Make_Struct(klass, fd_hash_t, &fd_hash_type, fd_hash);
62
+ filedict_init(&fd_hash->filedict);
63
+
64
+ return result;
65
+ }
66
+
67
+
68
+ /*
69
+ * ==============================
70
+ * Ruby method definitions
71
+ * ==============================
72
+ *
73
+ */
74
+
75
+ static VALUE fd_hash_initialize(VALUE self, VALUE filename) {
76
+ fd_hash_t *fd_hash = RTYPEDDATA_DATA(self);
77
+
78
+ const char *filename_cstr = StringValuePtr(filename);
79
+ filedict_open(&fd_hash->filedict, filename_cstr);
80
+
81
+ if (fd_hash->filedict.error) {
82
+ rb_raise(rb_eArgError, "Filedict error: %s", fd_hash->filedict.error);
83
+ }
84
+
85
+ return self;
86
+ }
87
+
88
+ static VALUE fd_set_add(int argc, VALUE *argv, VALUE self) {
89
+ VALUE fd_hash_ruby_object = rb_ivar_get(self, id_fd_hash);
90
+
91
+ if (fd_hash_ruby_object == Qnil) {
92
+ return self;
93
+ }
94
+
95
+ fd_hash_t *fd_hash = RTYPEDDATA_DATA(fd_hash_ruby_object);
96
+ int i;
97
+
98
+ VALUE key = rb_ivar_get(self, id_fd_key);
99
+ const char *key_cstr = StringValuePtr(key);
100
+ const char *value_cstr;
101
+
102
+ for (i = 0; i < argc; ++i) {
103
+ value_cstr = StringValuePtr(argv[i]);
104
+ filedict_insert_unique(&fd_hash->filedict, key_cstr, value_cstr);
105
+ }
106
+
107
+ return rb_call_super(argc, argv);
108
+ }
109
+
110
+ static VALUE fd_hash_access(VALUE self, VALUE key) {
111
+ fd_hash_t *fd_hash = RTYPEDDATA_DATA(self);
112
+
113
+ VALUE result = rb_class_new_instance(0, NULL, cSet);
114
+ const char *key_cstr = StringValuePtr(key);
115
+
116
+ filedict_read_t read = filedict_get(&fd_hash->filedict, key_cstr);
117
+
118
+ int success = 1;
119
+ while (success && read.value) {
120
+ rb_funcall(result, id_add, 1, rb_str_new_cstr(read.value));
121
+ success = filedict_get_next(&read);
122
+ }
123
+
124
+ rb_ivar_set(result, id_fd_hash, self);
125
+ rb_ivar_set(result, id_fd_key, key);
126
+
127
+ rb_extend_object(result, mSetExt);
128
+
129
+ return result;
130
+ }
131
+
132
+ void fdrb_init_hash() {
133
+ cHash = rb_define_class_under(mFiledict, "Hash", rb_cObject);
134
+ rb_define_alloc_func(cHash, fd_hash_allocate);
135
+
136
+ rb_define_method(cHash, "initialize", fd_hash_initialize, 1);
137
+ rb_define_method(cHash, "at", fd_hash_access, 1);
138
+ rb_define_method(cHash, "[]", fd_hash_access, 1);
139
+
140
+ VALUE rb_cSet = rb_define_class("Set", rb_cObject);
141
+ cSet = rb_define_class_under(mFiledict, "Set", rb_cSet);
142
+ mSetExt = rb_define_module_under(mFiledict, "SetExt");
143
+
144
+ rb_define_method(mSetExt, "add", fd_set_add, -1);
145
+
146
+ id_add = rb_intern("add");
147
+ id_remove = rb_intern("remove");
148
+ id_freeze = rb_intern("freeze");
149
+ id_fd_hash = rb_intern_const("__fd_hash__");
150
+ id_fd_key = rb_intern_const("__fd_hash_key__");
151
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef HASH_H
2
+ #define HASH_H 1
3
+
4
+ #include "filedictrb.h"
5
+
6
+ typedef struct fd_hash_t {
7
+ filedict_t filedict;
8
+ } fd_hash_t;
9
+
10
+ void fdrb_init_hash(void);
11
+
12
+ #endif /* HASH_H */
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/filedict/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "filedictrb"
7
+ spec.version = Filedict::VERSION
8
+ spec.authors = ["Nigel Baillie"]
9
+ spec.email = ["metreckk@gmail.com"]
10
+
11
+ spec.summary = "Uses filedict to emulate a file-backed Hash<Set<String>>"
12
+ spec.homepage = "https://github.com/Resonious/filedictrb"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ spec.extensions = ["ext/filedictrb/extconf.rb"]
32
+
33
+ # Uncomment to register a new dependency of your gem
34
+ # spec.add_dependency "example-gem", "~> 1.0"
35
+
36
+ # For more information and examples about making a new gem, checkout our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filedict
4
+ VERSION = "0.1.0"
5
+ end
data/lib/filedict.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require_relative 'filedict/version'
5
+ require_relative 'filedictrb/filedictrb'
6
+
7
+ module Filedict
8
+ class Error < StandardError; end
9
+ # Your code goes here...
10
+ end
data/lib/filedictrb.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'filedict'
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: filedictrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nigel Baillie
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-03-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - metreckk@gmail.com
16
+ executables: []
17
+ extensions:
18
+ - ext/filedictrb/extconf.rb
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - bin/console
28
+ - bin/setup
29
+ - ext/filedictrb/extconf.rb
30
+ - ext/filedictrb/filedictrb.c
31
+ - ext/filedictrb/filedictrb.h
32
+ - ext/filedictrb/hash.c
33
+ - ext/filedictrb/hash.h
34
+ - filedictrb.gemspec
35
+ - lib/filedict.rb
36
+ - lib/filedict/version.rb
37
+ - lib/filedictrb.rb
38
+ homepage: https://github.com/Resonious/filedictrb
39
+ licenses:
40
+ - MIT
41
+ metadata:
42
+ allowed_push_host: https://rubygems.org
43
+ homepage_uri: https://github.com/Resonious/filedictrb
44
+ source_code_uri: https://github.com/Resonious/filedictrb
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.4.0
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.3.3
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Uses filedict to emulate a file-backed Hash<Set<String>>
64
+ test_files: []