collabda 0.0.1a

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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/collabda.rb +113 -0
  3. data/spec/lib/collabda_spec.rb +179 -0
  4. metadata +60 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 72411f5cfca47c38d7810c6d0619bfb68fda266a
4
+ data.tar.gz: 5c73e2d894bbb0d1fbb64c7c527686a4826873f9
5
+ SHA512:
6
+ metadata.gz: 647e46c9f8395fd4e99d9534764073ec36408e77dc3663fc9af315872081056678ca2da94c0f41c614169cc78a908ff8dcb699fc6adcba41f0772973dfbc0255
7
+ data.tar.gz: 762fa5e7c1d0e82ca7937b9d13330c2667c44bdd0147ba78cc5aaadfc58b4af65a0e14de5f9de1c6512218cb3650f9ed4153ce5680354254df8925f32e2ffb5a
data/lib/collabda.rb ADDED
@@ -0,0 +1,113 @@
1
+ module Collabda
2
+ def self.included(base)
3
+ base.extend(Enumerable)
4
+ base.extend(ClassMethods)
5
+ @classes ||= []
6
+ @classes << base
7
+ end
8
+
9
+ def self.rebuild_collections
10
+ return if @classes.nil?
11
+ @classes.each do |c|
12
+ c.build_collection
13
+ end
14
+ end
15
+
16
+ def self.collection(class_name, &block)
17
+ model = Class.new do
18
+ include Collabda
19
+ self.class_eval(&block)
20
+ end
21
+ nesting = block.binding.eval("Module.nesting[0]") || Object
22
+ nesting.instance_eval{const_set(class_name, model)}
23
+ model.build_collection
24
+ return model
25
+ end
26
+
27
+ # def self.watch_files
28
+ # @classes.map{|c| c.source_path}
29
+ # end
30
+
31
+ InvalidSource = Class.new(StandardError)
32
+ MissingAttributes = Class.new(StandardError)
33
+
34
+ module ClassMethods
35
+ def source(path, options={})
36
+ @source_path = path
37
+ @format = options[:type] || :yaml
38
+ fetch_data
39
+ end
40
+
41
+ def all
42
+ @collabda_models
43
+ end
44
+
45
+ def each(&block)
46
+ all.each(&block)
47
+ end
48
+
49
+ def check_validity
50
+ raise InvalidSource if @source_path.nil?
51
+ raise MissingAttributes if @properties.nil?
52
+ end
53
+
54
+ def build_collection
55
+ check_validity
56
+ fetch_data
57
+ @collabda_models = @parsed_data.map do |el|
58
+ build(el)
59
+ end
60
+ end
61
+
62
+ def build(attributes_hash)
63
+ model = self.new
64
+ @properties.each do |attribute|
65
+ model.instance_variable_set("@#{attribute}",attributes_hash[attribute])
66
+ end
67
+ model
68
+ end
69
+
70
+ def properties(*attributes)
71
+ @properties=attributes
72
+ end
73
+
74
+ def source_path
75
+ @source_path
76
+ end
77
+
78
+ def parsed_data
79
+ @parsed_data
80
+ end
81
+
82
+ private
83
+ def fetch_data
84
+ io = File.open(@source_path)
85
+ @parsed_data = Readers.send(@format,io)
86
+ end
87
+ end
88
+
89
+ module Readers
90
+ def self.yaml(io)
91
+ YAML.load(io).map{|model| model.symbolize_keys}
92
+ end
93
+ def self.json(io)
94
+ JSON.load(io).map{|model| model.symbolize_keys}
95
+ end
96
+ end
97
+ end
98
+
99
+ if defined? Rails
100
+ # TODO: add development autoreload code
101
+ else
102
+ class Hash
103
+ def symbolize_keys
104
+ dup.symbolize_keys!
105
+ end
106
+ def symbolize_keys!
107
+ keys.each do |key|
108
+ self[(key.to_sym rescue key) || key] = delete(key)
109
+ end
110
+ self
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,179 @@
1
+ require 'collabda'
2
+
3
+ FOO_YAML = <<-yaml
4
+ - name: Foo
5
+ description: "yo foo"
6
+ - name: Bar
7
+ description: "at the bar"
8
+ - name: Baz
9
+ description: "get some baz"
10
+ yaml
11
+
12
+ FOO_JSON = <<-json
13
+ [
14
+ {"name": "FooJ", "description": "yo foo"},
15
+ {"name": "BarJ", "description": "at the bar"},
16
+ {"name": "BazJ", "description": "get some baz"}
17
+ ]
18
+ json
19
+
20
+ describe "Collabda" do
21
+ before(:each) do
22
+ File.stub(:open){StringIO.open(FOO_YAML)}
23
+ end
24
+
25
+ let(:class_builder) do
26
+ ->(&block) do
27
+ -> do
28
+ Class.new do
29
+ include Collabda
30
+ # include Collabda::Document
31
+ block.call(self)
32
+ attr_reader :description
33
+ properties :name, :description
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ let(:yaml_class_factory) do
40
+ class_builder.call{|c| c.source "spec/lib/foo.yaml", :type=>:yaml}
41
+ end
42
+
43
+
44
+ it "opens specified file during class definition" do
45
+ File.should_receive(:open)
46
+ model_class = yaml_class_factory.call
47
+ end
48
+
49
+ describe "errors" do
50
+ let(:model_class){Class.new{include Collabda}}
51
+ it "raises InvalidSource error if source not set" do
52
+ expect{model_class.build_collection}.to raise_error Collabda::InvalidSource
53
+ end
54
+ it "raises MissingAttributes error if not set" do
55
+ model_class.source "foo.yaml"
56
+ expect{model_class.build_collection}.to raise_error Collabda::MissingAttributes
57
+ end
58
+ end
59
+
60
+ describe "Yaml model" do
61
+ let!(:model_class){yaml_class_factory.call}
62
+ specify "source sets a source_path class variable" do
63
+ expect(model_class.source_path).to be_a String
64
+ end
65
+
66
+ specify "properties sets fields to use" do
67
+ expect(model_class.instance_variable_get(:@properties)).to eq [:name, :description]
68
+ end
69
+
70
+ it "tracks where Collabda is included" do
71
+ FooList = model_class
72
+ expect(Collabda.instance_variable_get(:@classes)).to include FooList
73
+ end
74
+
75
+ # it "maintains a list of yaml files to watch" do
76
+ # expect(Collabda.watch_files).to include "spec/lib/foo.yaml"
77
+ # end
78
+
79
+ it "loads yaml data from file" do
80
+ expect(model_class.parsed_data.count).to eq 3
81
+ end
82
+
83
+ it "uses symbols as attribute keys for consistency" do
84
+ expect(model_class.parsed_data.first.keys.first).to be_a Symbol
85
+ end
86
+
87
+ it "builds a new model for each element in the data" do
88
+ model_class.should_receive(:new).exactly(3).times.and_return(double(:test))
89
+ model_class.build_collection
90
+ end
91
+
92
+ it "reloads the yaml file on build_collection" do
93
+ model_class.should_receive(:fetch_data).and_call_original
94
+ model_class.build_collection
95
+ end
96
+
97
+ it "can build a new instance from an attributes hash, bypassing yaml" do
98
+ instance = model_class.build(:name=>"Bat",:description=>"man")
99
+ expect(instance.description).to eq "man"
100
+ end
101
+
102
+ context "when collection built" do
103
+ before(:each){model_class.build_collection}
104
+ it "it provides access to all models" do
105
+ expect(model_class.all.count).to eq 3
106
+ expect(model_class.all.first.class).to eq model_class
107
+ end
108
+
109
+ it "sets instance variables for each yaml attribute" do
110
+ expect(model_class.all.first.instance_variable_get(:@name)).to eq "Foo"
111
+ end
112
+
113
+ it "implements enumerable correctly" do
114
+ expect(model_class.map{|m| m.instance_variable_get(:@name)}).to eq ["Foo","Bar","Baz"]
115
+ end
116
+
117
+ it "works alongside attr_reader" do
118
+ expect(model_class.first.description).to eq "yo foo"
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "Json model" do
124
+ before(:each) do
125
+ File.stub(:open){StringIO.open(FOO_JSON)}
126
+ end
127
+ let(:json_class_factory) do
128
+ class_builder.call{|c| c.source "http://foo.bar/baz.json", :type=>:json}
129
+ end
130
+ it "parses json into ruby data" do
131
+ model_class = json_class_factory.call
132
+ expect(model_class.parsed_data.first[:name]).to eq "FooJ"
133
+ end
134
+ end
135
+
136
+ describe "collection" do
137
+ let(:built_collection) do
138
+ Collabda.collection(:Food) do
139
+ source ""
140
+ properties :none
141
+ def foo
142
+ end
143
+ def self.bar
144
+ end
145
+ end
146
+ end
147
+
148
+ after(:each){Object.send(:remove_const,:Food) rescue nil}
149
+
150
+ it "creates a class in parent context" do
151
+ built_collection = module TestModels
152
+ class C
153
+ Collabda.collection(:Food){source "";properties :none}
154
+ end
155
+ end
156
+ expect(built_collection.to_s).to eq "TestModels::C::Food"
157
+ end
158
+
159
+ it "creates a class root context if not in module" do
160
+ expect(built_collection.to_s).to eq "Food"
161
+ end
162
+
163
+ it "includes Collabda in the new class" do
164
+ expect(built_collection).to respond_to :source
165
+ end
166
+
167
+ it "executes its block while building the class" do
168
+ expect(built_collection).to respond_to :bar
169
+ end
170
+
171
+ it "executes is block in the correct context" do
172
+ expect(built_collection.new).to respond_to :foo
173
+ end
174
+
175
+ it "auto-builds the collection from its source" do
176
+ expect{Collabda.collection(:Food){}}.to raise_error Collabda::InvalidSource
177
+ end
178
+ end
179
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: collabda
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1a
5
+ platform: ruby
6
+ authors:
7
+ - James Edwards-Jones
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ description: Collabda uses JSON or YAML files to build a collection of classes.
28
+ email:
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/collabda.rb
34
+ - spec/lib/collabda_spec.rb
35
+ homepage: https://github.com/Jamedjo/Collabda
36
+ licenses:
37
+ - Apache-2.0
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>'
51
+ - !ruby/object:Gem::Version
52
+ version: 1.3.1
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.1.9
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: A library for building models from data files
59
+ test_files:
60
+ - spec/lib/collabda_spec.rb