rffdb 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc32e7e6da39ca78200a564f07ababf89cb3749f
4
- data.tar.gz: a9978b86ec538b44b238e10e32fa85bb4bc83136
3
+ metadata.gz: 1663bc00dcb1ccd67c4e62f73367682709c603b3
4
+ data.tar.gz: ba8637b384bb8215977d852b5e1f0e483fd0f638
5
5
  SHA512:
6
- metadata.gz: 8220e8ef033aa49a605148edf591334d6449e569ca38a3a823b2b6019759d077e390a3be3e1d6e5c718b22e79eeecf9a3c0b42443fb057c16748f40978b2fd22
7
- data.tar.gz: 84ccd13638927c947da052720ffda3fcd50869a0a267308f5c9a6e466deebbb8a908929b31bba261a839f60b1bdd9048878f981b7d19e360dc0cd888b7409dfb
6
+ metadata.gz: 013ed8f87707dc0e6f71909951e646e20fc682d5851c60a447bff9975bd5e8620a7bc0b86a8d6a70b28150dd5a06935c26d119e3891af4959413cd370b12cccd
7
+ data.tar.gz: 98985078b1ed11cf51a28d11f1355b5ac056f8c82336f8af7229a935fd726cbe188c4d96b0ee6582b446b7ad419fcb033cda43c7fd03300f9d312c10025359b6
data/README.markdown ADDED
@@ -0,0 +1,167 @@
1
+ Ruby Flat File DB
2
+ =================
3
+
4
+ About
5
+ -----
6
+ This is a really horrible idea for anything requiring high performance, but it is a pretty good way to demonstrate how to create a gem and simple framework in Ruby. This is meant to emulate ActiveRecord or DataMapper, without all the performance, scalabilty, and thread-safety concerns, and meant to be used with really poor database storage formats, like YAML or JSON. **Pay attention to this:** This is a demonstration of Ruby and frameworks, and not to be used in any kind of production environment.
7
+
8
+ The gem is currently built around the concepts of "documents" and "storage engines". The rffdb gem is built to allow defining and choosing "storage engines" per database model. Database models are subclasses of the `Document` class, and storage engines are subclasses of the `StorageEngine` class.
9
+
10
+ Some interesting concepts have been introduced (mostly to experiment), such as lazy-loading of model data, a caching layer between model instances and their persistent storage (a simple LRU Cache per model as an instance of `RubyFFDB::CacheProviders::LRUCache`, of course), with more to come. I plan on eventually adding thread-safety through the use of more singletons, with a semaphore or mutex around the persistent storage (with a non-blocking storage pool as an eventual option), indexes and other metadata, full-text search, and maybe someday an embedded web service for serving up the FFDB.
11
+
12
+ Building
13
+ -----
14
+
15
+ While it is recommended to simply install via a normal rubygems search via ` gem install rffdb` (or adding `gem "rffdb"` to your Gemfile), you can build and install the gem yourself. This can be done like so:
16
+
17
+ #!bash
18
+ # need Mercurial to clone the repo... or download it from https://bitbucket.org/jgnagy/rffdb/get/tip.zip
19
+ hg clone https://bitbucket.org/jgnagy/rffdb
20
+ cd rffdb
21
+ # highly recommend using RVM here, and Ruby 2.x or above
22
+ gem build rffdb.gemspec
23
+ # install what you just built
24
+ gem install ./rffdb-*.gem
25
+
26
+ Sometimes you might get lucky and there's a semi-recent version of the pre-built gem available on bitbucket [here](https://bitbucket.org/jgnagy/rffdb/downloads).
27
+
28
+ Usage
29
+ -----
30
+
31
+ Require the right gem(s):
32
+
33
+ #!ruby
34
+ require 'rffdb'
35
+
36
+ The `YamlEngine` storage engine is included by default. To include additional storage engines (like the JSON engine), just require them:
37
+
38
+ #!ruby
39
+ require 'rffdb/storage_engines/json_engine'
40
+
41
+ Now you must define a document model. Let's call this model "Product", like we're making an app to sell things:
42
+
43
+ #!ruby
44
+ class Product < RubyFFDB::Document
45
+ end
46
+
47
+ Now that's a pretty lame document, because all it has is an "id" attribute:
48
+
49
+ #!ruby
50
+ product = Product.new
51
+ product.id # => 1
52
+
53
+ Let's start over, and this time make it better:
54
+
55
+ #!ruby
56
+ class Product < RubyFFDB::Document
57
+ attribute :name, :class => String
58
+ attribute :price, :class => Float
59
+ attribute :style, :class => String
60
+ attribute :description, :class => String
61
+ end
62
+
63
+ Now our Product class can do more interesting things, like store data. Yay! Here's how we use it:
64
+
65
+ #!ruby
66
+ product = Product.new
67
+ product.name = "Awesome Sauce 5000"
68
+ product.price = 19.95
69
+ product.style = "saucy"
70
+ product.description = "A sauce above the rest. Easily 10x more awesome than any other sauce."
71
+ product.commit # or product.save
72
+
73
+ Now to pull it up later:
74
+
75
+ #!ruby
76
+ product = Product.get(1)
77
+ product.price # => 19.95
78
+
79
+ If you suspect someone else has written to the file, or that it has otherwise changed since you last loaded it, just refresh it:
80
+
81
+ #!ruby
82
+ product.refresh
83
+
84
+ If you want to make another model that uses a different storage engine, just specify the class when you define the model:
85
+
86
+ #!ruby
87
+ class Customer < RubyFFDB::Document
88
+ engine RubyFFDB::StorageEngines::JsonEngine # default is RubyFFDB::StorageEngines::YamlEngine
89
+
90
+ attribute :address, :class => String
91
+ attribute :first_name, :class => String
92
+ attribute :last_name, :class => String
93
+ attribute :phone_number, :class => String
94
+ attribute :email, :class => String, :format => /[a-zA-Z0-9_.+-]{2,}[a-zA-Z0-9]@([a-zA-Z0-9_.+-]{2,}[a-zA-Z0-9])+/
95
+ end
96
+
97
+ customer = Customer.new
98
+ customer.email = "abcd"
99
+ # RubyFFDB::Exceptions::InvalidInput raised
100
+
101
+ Whoa, see what just happened? We used a different storage engine, and we validated the format of email addresses! That's right, attributes support specifying a format for Strings using a regular expression. You can also have it execute arbitrary validations (defined in the model class) as long as they're methods that accept a single input: the value you're attempting to set the attribute to:
102
+
103
+ #!ruby
104
+ class Payment < RubyFFDB::Document
105
+ # The "engine" DSL method also provides a means to customize caching
106
+ engine RubyFFDB::StorageEngines::JsonEngine,
107
+ :cache_provider => RubyFFDB::CacheProviders::RRCache,
108
+ :cache_size => 200
109
+ attribute :cc_vendor, :class => String, :validate => :valid_payment_methods
110
+ attribute :amount, :class => Float
111
+
112
+ def valid_payment_methods(payment_method)
113
+ ['visa', 'master card'].include? payment_method
114
+ end
115
+ end
116
+
117
+ payment = Payment.new
118
+ payment.amount = 22.17
119
+ payment.cc_vendor = "amex"
120
+ # RubyFFDB::Exceptions::FailedValidation raised
121
+
122
+ Instances of `Document` (or its collection class, `DocumentCollection`) support querying via attributes:
123
+
124
+ #!ruby
125
+ # All payments... ever
126
+ payments = Payments.all
127
+
128
+ # Just payments made with Visa
129
+ visa_payments = Payments.where(:cc_vendor, 'visa')
130
+
131
+ # Just visa payments of more than $100
132
+ # Notice we can just query an existing collection
133
+ # Also note the clunky syntax. You specify "attribute", then "value", then the comparison method.
134
+ # Valid comparison methods include: '>', '>=', '<', '<=', '==', or the special 'match' method.
135
+ big_visa_payments = visa_payments.where(:amount, 100.00, '>')
136
+
137
+ # Just master card payments of less than $10
138
+ # Notice that AND queries are just chaining WHERE queries
139
+ little_mc_payments = Payments.where(:amount, 10.00, '<').where(:cc_vendor, 'master card')
140
+
141
+ The possibilities are endless, but this is it for now.
142
+
143
+ License
144
+ -------
145
+
146
+ RubyFFDB is distributed under the MIT License
147
+
148
+ To Do
149
+ -----
150
+
151
+ * YARD documentation on everything
152
+ * Thread-safety
153
+ * Thread-pool for non-blocking / asynchronous writing to disk (must be optional and default to disabled)
154
+ * Indexing of columns, defined at model
155
+ * Full-text searchable fields, configured on model
156
+ * Write a method for clearing cache (globally and at the Model level) and invalidating individual instances (at the instance level)
157
+ * Add a way of disabling lazy-loading of data from disk at the model level
158
+ * Add "order_by" and a method for pagination of results (like LIMIT)
159
+ * Additional cache providers (at least SLRU and LFU)
160
+ * More Storage Engines (perhaps XML)
161
+
162
+ Contributing
163
+ ------------
164
+
165
+ Honestly, the point of this framework is for my own personal growth and learning. I'm trying hard to build the features I want into the framework without relying on the guts of other tools. I clearly rip off the methods exposed by other tools (meaning I'm designing a framework that you can interact with in a familiar way), but I'm trying to do it without knowing _how_ others did it.
166
+
167
+ That said, I welcome pull-requests. I may or may not use your code, but I encourage the growth of others too. If this project inspires you to contribute, feel free to fork my code and submit a pull request. If you're okay with the MIT license and you're open to me shamelessly claiming your code as my own (it'd have to be a pretty amazing contribution for your name to show up anywhere but the commit history), go for it.
@@ -0,0 +1,4 @@
1
+ module RubyFFDB
2
+ # Data directory for DB storage
3
+ DB_DATA = ENV["RFFDB_DB_DATA"] ? File.expand_path(ENV["RFFDB_DB_DATA"]) : File.expand_path(File.join("~", ".rffdb", "data"))
4
+ end
@@ -45,7 +45,7 @@ module RubyFFDB
45
45
  end
46
46
 
47
47
  def self.file_path(type, object_id)
48
- File.join(type.to_s.gsub('::', "__"), 'documents', object_id.to_s + ".json")
48
+ File.join(DB_DATA, type.to_s.gsub('::', "__"), 'documents', object_id.to_s + ".json")
49
49
  end
50
50
  end
51
51
  end
@@ -43,7 +43,7 @@ module RubyFFDB
43
43
  end
44
44
 
45
45
  def self.file_path(type, object_id)
46
- File.join(type.to_s.gsub('::', "__"), 'documents', object_id.to_s + ".yml")
46
+ File.join(DB_DATA, type.to_s.gsub('::', "__"), 'documents', object_id.to_s + ".yml")
47
47
  end
48
48
  end
49
49
  end
data/lib/rffdb/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RubyFFDB
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
data/lib/rffdb.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'ostruct'
2
2
  require 'rffdb/version'
3
+ require 'rffdb/constants'
3
4
  require 'rffdb/exception'
4
5
  require 'rffdb/exceptions/cache_exceptions'
5
6
  require 'rffdb/exceptions/document_exceptions'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rffdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
@@ -17,10 +17,12 @@ extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
19
  - LICENSE
20
+ - README.markdown
20
21
  - lib/rffdb.rb
21
22
  - lib/rffdb/cache_provider.rb
22
23
  - lib/rffdb/cache_providers/lru_cache.rb
23
24
  - lib/rffdb/cache_providers/rr_cache.rb
25
+ - lib/rffdb/constants.rb
24
26
  - lib/rffdb/document.rb
25
27
  - lib/rffdb/document_collection.rb
26
28
  - lib/rffdb/exception.rb