mementus 0.0.1 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDQ4NmJhMTc1NTk1ZTk3MWExOWQyMDdiNWFlODE0M2RhN2MyOGFjMA==
4
+ Mzg4MDg1OTYxZjllZGJiMWM1OGFjODc5MTcyNDQ1YzIyYmU3NzgwMA==
5
5
  data.tar.gz: !binary |-
6
- NWZiZjNiMzdjNzNjNjEzNDQ3MmZmOWRhZjI3OTAzOTI0YTk5ZWQzNg==
6
+ YjcyZWZiNGE0ZTllMWU2MzI1Nzc1Yjg1ZDlkMGUzZGQxMTkyOWJhNg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OTUxYjFiNzY1YzUxMjczMTQ5MzhkNjQzZTZhM2NjMGQwNzhhNjEyYzVkYzZm
10
- ZWNmMGYwNGZkZmU3ZDRkNWQ0ZmIzZWFlMTg1OGY1ZGUwOTlkOWNiOGVkZjcz
11
- OTcwMzdhMGE3YTU3MzkyYzhlZjExZDMxZTU1Mzk1NjJhNzk4ODc=
9
+ YjIyNDEyNTQyZWQwYzgzMzhlMzEzYTI5MzQyZDQ2YjE3MGQwYTZmMTljY2Vm
10
+ MTIxZGVhMDJmYjQ2NWE3MTFjYWU0YjQxYWUyYTgyZTAxODEwM2UwNmIyNzM5
11
+ YzI3MzI2ZmY4NjU5YmEyMTA4OTg3ZDBlNDM3MzFjZGY3MTVmZTg=
12
12
  data.tar.gz: !binary |-
13
- ZWRmYmIyMjVhYTdlM2QwYjU3OWJmMjMxOTQ1Mjc4MTE2NWQwZDM4NGZjMjI5
14
- NWFhMGU0ZWM4YmJmNjJjMTBkYWI2ZjgzYjBkYjhhZTU5NmNmNzEzODE5MDM0
15
- ZDM0ZjkxNmZjYjMwODdjNWU2M2MzNmU2N2IwOTE3ZGZjMzZkNWM=
13
+ NjZjOGRkZWZhMjE0MDVhM2NhZjk1NDg3NDE3N2JiYzBmMGVmMGY4NDQ5M2Zj
14
+ N2Y0ZWQ5Y2QyNGRmZWY4YzdhOTJkOWIxNzA5OTYyY2JmOGZmZTJhNWM0ZGU0
15
+ ZGI3N2NlYzYxYWQwZDUyMDY2NTU2ZjRkMmQwMmIxZTNkNTlhYzc=
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+
3
+ cache: bundler
4
+
5
+ rvm:
6
+ - 2.1
7
+ - 2.0
8
+ - 1.9.3
9
+
10
+ script: bundle exec rspec
data/README.md CHANGED
@@ -1,6 +1,21 @@
1
1
  # Mementus
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/maetl/mementus.svg?branch=master)](https://travis-ci.org/maetl/mementus)
4
+
5
+ ```ruby
6
+ # Proof of concept for a toy ORM that combines some aspects of the
7
+ # ActiveRecord API with an in-memory query model based on the Axiom
8
+ # relational algebra API.
9
+ #
10
+ # The weirdest trick is that the data stored in the relational model
11
+ # is a read-only index that never gets re-materialised back into the
12
+ # model objects themselves (though Axiom does seem to be capable of
13
+ # doing this).
14
+ #
15
+ # Instead of returning mapped data from queries, the Ruby object_id
16
+ # is used as a reference to point to the existing instance in the
17
+ # runtime object space.
18
+ ```
4
19
 
5
20
  ## Installation
6
21
 
@@ -18,7 +33,50 @@ Or install it yourself as:
18
33
 
19
34
  ## Usage
20
35
 
21
- TODO: Write usage instructions here
36
+ To define model classes, inherit from the `Mementus::Model` base class and add attributes using the [Virtus API](https://github.com/solnic/virtus):
37
+
38
+ ```ruby
39
+ class Book < Mementus::Model
40
+ attribute :title, String
41
+ attribute :author, String
42
+ end
43
+ ```
44
+
45
+ Create new instances by passing data through the constructor or assigning attributes directly:
46
+
47
+ ```ruby
48
+ book1 = Book.new(
49
+ :title => "Gravity's Rainbow",
50
+ :author => "Thomas Pynchon"
51
+ )
52
+
53
+ book2 = Book.new
54
+ book2.title = "The Golden Notebook"
55
+ book2.author = "Doris Lessing"
56
+ ```
57
+
58
+ To write objects to the in-memory index, call their `create` method:
59
+
60
+ ```ruby
61
+ book3 = Book.new(
62
+ :title => "Crash",
63
+ :author => "J.G. Ballard"
64
+ )
65
+
66
+ book3.create
67
+ ```
68
+
69
+ The query API is currently being worked on. Right now to test it out, you can access the relational collection for each model through the `collection` method, and execute basic matching queries using the `where` method:
70
+
71
+ ```ruby
72
+ Book.collection.count
73
+
74
+ Book.collection.first
75
+
76
+ Book.where(author: "Doris Lessing")
77
+
78
+ Book.where(title: "Crash")
79
+ ```
22
80
 
23
81
  ## Contributing
24
82
 
@@ -0,0 +1,105 @@
1
+ require 'virtus'
2
+ require 'axiom-memory-adapter'
3
+
4
+ module Mementus
5
+
6
+ # Proof of concept for a toy ORM that combines some aspects of the
7
+ # ActiveRecord API with an in-memory query model based on the Axiom
8
+ # relational algebra API.
9
+ #
10
+ # The weirdest trick is that the data stored in the relational model
11
+ # is a read-only index that never gets re-materialised back into the
12
+ # model objects themselves (though Axiom does seem to be capable of
13
+ # doing this).
14
+ #
15
+ # Instead of returning mapped data from queries, the Ruby object_id
16
+ # is used as a reference to point to the existing instance in the
17
+ # runtime object space.
18
+ #
19
+ class Model
20
+
21
+ @@local_storage = nil
22
+ @@model_registry = {}
23
+
24
+ def self.name_to_sym
25
+ name_without_namespace = name.split("::").last
26
+ name_without_namespace.gsub(/([^\^])([A-Z])/,'\1_\2').downcase.to_sym
27
+ end
28
+
29
+ # TODO: this mapping could be based on declared indexes,
30
+ # rather than dumping the entire attribute schema here.
31
+ #
32
+ def schema_tuple
33
+ tuple = [[:__object_id, String]]
34
+ attribute_set.each do |attribute_type|
35
+ tuple << [attribute_type.name.to_sym, attribute_type.primitive]
36
+ end
37
+ tuple
38
+ end
39
+
40
+ # TODO: this mapping could be based on declared indexes,
41
+ # rather than dumping the entire attribute data set here.
42
+ #
43
+ def values_tuple
44
+ tuple = [object_id.to_s]
45
+ attributes.each do |_, attribute_value|
46
+ tuple << attribute_value
47
+ end
48
+ tuple
49
+ end
50
+
51
+ def self.inherited(concrete_model)
52
+ concrete_model.send(:include, Virtus.model)
53
+ end
54
+
55
+ # Create only writes to memory. It's required in order to
56
+ # index the object's attributes in the query model.
57
+ #
58
+ def create
59
+ ensure_registered(self)
60
+ local_storage[self.class.name_to_sym].insert([values_tuple])
61
+ end
62
+
63
+ def ensure_registered(model)
64
+ register(model) unless registered?(model)
65
+ end
66
+
67
+ def registered?(model)
68
+ model_registry.has_key? model.class.name_to_sym
69
+ end
70
+
71
+ def register(model)
72
+ model_id = model.class.name_to_sym
73
+ model_registry[model_id] = true
74
+ local_storage[model_id] = Axiom::Relation.new(model.schema_tuple)
75
+ end
76
+
77
+ def model_registry
78
+ @@model_registry
79
+ end
80
+
81
+ def local_storage
82
+ unless @@local_storage
83
+ @@local_storage = Axiom::Adapter::Memory.new
84
+ end
85
+ @@local_storage
86
+ end
87
+
88
+ def self.collection
89
+ @@local_storage[name_to_sym]
90
+ end
91
+
92
+ # Stub implementation that demonstrates the ObjectSpace
93
+ # reference grabbing.
94
+ #
95
+ # Currently just splats to an array instead of handing back
96
+ # a chainable scope object.
97
+ #
98
+ def self.where(constraints)
99
+ self.collection.restrict(constraints).inject([]) do |list, relation|
100
+ list << ObjectSpace._id2ref(relation[:__object_id].to_i)
101
+ end
102
+ end
103
+
104
+ end
105
+ end
@@ -1,3 +1,3 @@
1
1
  module Mementus
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/mementus.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "mementus/version"
1
+ require 'virtus'
2
+ require 'axiom-memory-adapter'
2
3
 
3
- module Mementus
4
- # Your code goes here...
5
- end
4
+ require_relative 'mementus/version'
5
+ require_relative 'mementus/model'
data/mementus.gemspec CHANGED
@@ -18,6 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_runtime_dependency "virtus"
22
+ spec.add_runtime_dependency "axiom-memory-adapter"
23
+
21
24
  spec.add_development_dependency "bundler", "~> 1.3"
22
25
  spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
23
27
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mementus::Model do
4
+
5
+ describe "Attributes" do
6
+
7
+ class PrimaryAttributes < Mementus::Model
8
+ attribute :name, String
9
+ attribute :count, Integer
10
+ attribute :switch, Boolean
11
+ end
12
+
13
+ let(:model) {
14
+ PrimaryAttributes.new(
15
+ :name => "a string",
16
+ :count => 500,
17
+ :switch => false
18
+ )
19
+ }
20
+
21
+ it "reads attributes" do
22
+ expect(model.name).to eq "a string"
23
+ expect(model.count).to eq 500
24
+ expect(model.switch).to eq false
25
+ end
26
+
27
+ it "writes attributes" do
28
+ model.name = "stringstringstring"
29
+ model.count = 488
30
+ model.switch = true
31
+
32
+ expect(model.name).to eq "stringstringstring"
33
+ expect(model.count).to eq 488
34
+ expect(model.switch).to eq true
35
+ end
36
+
37
+ end
38
+
39
+
40
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mementus::Model do
4
+
5
+ describe "Collection" do
6
+
7
+ class Item < Mementus::Model
8
+ attribute :name, String
9
+ attribute :order, Integer
10
+ end
11
+
12
+ before(:all) do
13
+ 20.times do |i|
14
+ item = Item.new
15
+ item.name = "Item: #{i.to_s}"
16
+ item.order = i + 1
17
+ item.create
18
+ end
19
+ end
20
+
21
+ it "counts created items" do
22
+ expect(Item.collection.count).to eq 20
23
+ end
24
+
25
+ it "finds item by matching attribute" do
26
+ expect(Item.where(order: 10).count).to eq 1
27
+ expect(Item.where(order: 10).first.name).to eq "Item: 9"
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mementus::Model do
4
+
5
+ describe "Mapping" do
6
+
7
+ class Mapping < Mementus::Model
8
+ attribute :description, String
9
+ attribute :number, Integer
10
+ end
11
+
12
+ let(:mapping) {
13
+ Mapping.new(
14
+ :description => "Hello world.",
15
+ :number => 2014
16
+ )
17
+ }
18
+
19
+ let(:object_id) {
20
+ mapping.object_id.to_s
21
+ }
22
+
23
+ it "maps attribute schema to tuple" do
24
+ schema = [[:__object_id, String], [:description, String], [:number, Integer]]
25
+ expect(mapping.schema_tuple).to eq schema
26
+ end
27
+
28
+ it "maps attribute values to tuple" do
29
+ values = [object_id, "Hello world.", 2014]
30
+ expect(mapping.values_tuple).to eq values
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'mementus'
3
+
4
+ RSpec.configure do |config|
5
+ config.formatter = 'documentation'
6
+ end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mementus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - maetl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-10 00:00:00.000000000 Z
11
+ date: 2014-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: virtus
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: axiom-memory-adapter
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - ! '>='
39
67
  - !ruby/object:Gem::Version
40
68
  version: '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: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  description: In-memory data model
42
84
  email:
43
85
  - me@maetl.net
@@ -46,13 +88,19 @@ extensions: []
46
88
  extra_rdoc_files: []
47
89
  files:
48
90
  - .gitignore
91
+ - .travis.yml
49
92
  - Gemfile
50
93
  - LICENSE.txt
51
94
  - README.md
52
95
  - Rakefile
53
96
  - lib/mementus.rb
97
+ - lib/mementus/model.rb
54
98
  - lib/mementus/version.rb
55
99
  - mementus.gemspec
100
+ - spec/attribute_spec.rb
101
+ - spec/collection_spec.rb
102
+ - spec/mapping_spec.rb
103
+ - spec/spec_helper.rb
56
104
  homepage: ''
57
105
  licenses:
58
106
  - MIT
@@ -77,4 +125,8 @@ rubygems_version: 2.1.8
77
125
  signing_key:
78
126
  specification_version: 4
79
127
  summary: In-memory data model
80
- test_files: []
128
+ test_files:
129
+ - spec/attribute_spec.rb
130
+ - spec/collection_spec.rb
131
+ - spec/mapping_spec.rb
132
+ - spec/spec_helper.rb