opal-vienna 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +7 -0
  5. data/README.md +294 -0
  6. data/Rakefile +7 -0
  7. data/config.ru +8 -0
  8. data/lib/opal-vienna.rb +1 -0
  9. data/lib/opal/vienna.rb +7 -0
  10. data/lib/opal/vienna/version.rb +5 -0
  11. data/opal-vienna.gemspec +26 -0
  12. data/opal/vienna.rb +5 -0
  13. data/opal/vienna/adapters/base.rb +45 -0
  14. data/opal/vienna/adapters/local.rb +50 -0
  15. data/opal/vienna/adapters/rest.rb +97 -0
  16. data/opal/vienna/eventable.rb +35 -0
  17. data/opal/vienna/history_router.rb +44 -0
  18. data/opal/vienna/model.rb +222 -0
  19. data/opal/vienna/observable.rb +90 -0
  20. data/opal/vienna/observable_array.rb +73 -0
  21. data/opal/vienna/output_buffer.rb +13 -0
  22. data/opal/vienna/record_array.rb +31 -0
  23. data/opal/vienna/router.rb +85 -0
  24. data/opal/vienna/template_view.rb +41 -0
  25. data/opal/vienna/view.rb +93 -0
  26. data/spec/eventable_spec.rb +94 -0
  27. data/spec/history_router_spec.rb +47 -0
  28. data/spec/model/accessing_attributes_spec.rb +29 -0
  29. data/spec/model/as_json_spec.rb +28 -0
  30. data/spec/model/attribute_spec.rb +22 -0
  31. data/spec/model/initialize_spec.rb +42 -0
  32. data/spec/model/load_spec.rb +17 -0
  33. data/spec/model/persistence_spec.rb +84 -0
  34. data/spec/model_spec.rb +84 -0
  35. data/spec/observable_array_spec.rb +130 -0
  36. data/spec/observable_spec.rb +116 -0
  37. data/spec/output_buffer_spec.rb +37 -0
  38. data/spec/record_array_spec.rb +50 -0
  39. data/spec/route_spec.rb +89 -0
  40. data/spec/router_spec.rb +103 -0
  41. data/spec/spec_helper.rb +53 -0
  42. data/spec/template_view_spec.rb +47 -0
  43. data/spec/vendor/jquery.js +2 -0
  44. data/spec/view_spec.rb +78 -0
  45. metadata +181 -0
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ class AccessingAttributesSpec < Vienna::Model
4
+ attributes :first_name, :last_name
5
+
6
+ def last_name=(name)
7
+ raise "Cannot set last_name"
8
+ end
9
+ end
10
+
11
+ describe Vienna::Model do
12
+
13
+ let(:model) { AccessingAttributesSpec.new }
14
+
15
+ describe "#[]" do
16
+ it "retrieves attributes from the model" do
17
+ model[:first_name].should be_nil
18
+ model.first_name = "Adam"
19
+ model[:first_name].should eq("Adam")
20
+ end
21
+ end
22
+
23
+ describe "#[]=" do
24
+ it "sets attributes on the model" do
25
+ model[:first_name] = "Adam"
26
+ model.first_name.should eq("Adam")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vienna::Model do
4
+ describe "#as_json" do
5
+ let(:model) { User.new }
6
+
7
+ it "returns a hash" do
8
+ expect(model.as_json).to be_kind_of(Hash)
9
+ end
10
+
11
+ it "contains all attributes on model" do
12
+ expect(model.as_json).to eq({ "foo" => nil, "bar" => nil, "baz" => nil })
13
+
14
+ model.foo = "Adam"
15
+ expect(model.as_json).to eq({ "foo" => "Adam", "bar" => nil, "baz" => nil })
16
+
17
+ model.bar = "Beynon"
18
+
19
+ expect(model.as_json).to eq({ "foo" => "Adam", "bar" => "Beynon", "baz" => nil })
20
+ end
21
+
22
+ it "includes the id, if set" do
23
+ model.id = 42
24
+
25
+ expect(model.as_json).to eq({ "id" => 42, "foo" => nil, "bar" => nil, "baz" => nil })
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Vienna::Model do
4
+ describe ".attribute" do
5
+ let(:model) { User.new }
6
+
7
+ it "should create a reader method for attribute" do
8
+ expect(model).to respond_to(:foo)
9
+ end
10
+
11
+ it "should create a writer method for attribute" do
12
+ expect(model).to respond_to(:foo=)
13
+ end
14
+
15
+ describe "writer" do
16
+ it "sets value on model" do
17
+ model.foo = 'Tommy'
18
+ expect(model.foo).to eq('Tommy')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ describe Vienna::Model do
4
+ describe "#initialize" do
5
+ it "should have all nil values for attributes when passed no attrs" do
6
+ model = User.new
7
+
8
+ expect(model.foo).to be_nil
9
+ expect(model.bar).to be_nil
10
+ expect(model.baz).to be_nil
11
+ end
12
+
13
+ it "should set a given value for a given attributes" do
14
+ model = User.new foo: 3.142
15
+
16
+ expect(model.foo).to eq(3.142)
17
+ expect(model.bar).to be_nil
18
+ expect(model.baz).to be_nil
19
+ end
20
+
21
+ it "should be able to set many attributes" do
22
+ model = User.new foo: 'hello', bar: 'world', baz: 42
23
+
24
+ expect(model.foo).to eq('hello')
25
+ expect(model.bar).to eq('world')
26
+ expect(model.baz).to eq(42)
27
+ end
28
+
29
+ it "creates @attributes as an empty hash" do
30
+ model = User.new
31
+ model.instance_variable_get(:@attributes).should eq({})
32
+ end
33
+
34
+ it "marks the model as being a new record" do
35
+ expect(User.new).to be_new_record
36
+ end
37
+
38
+ it "marks the model as not being loaded" do
39
+ expect(User.new).to_not be_loaded
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vienna::Model do
4
+ describe "#load" do
5
+ let(:model) { SimpleModel.new }
6
+
7
+ it "marks the model instance as loaded" do
8
+ model.load({})
9
+ expect(model).to be_loaded
10
+ end
11
+
12
+ it "marks the model as not being a new record" do
13
+ model.load({})
14
+ expect(model).to_not be_new_record
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vienna::Model do
4
+ let(:model_class) { SimpleModel }
5
+ let(:model) { model_class.new }
6
+ let(:loaded_model) { model_class.load(:first_name => "Adam", id: 872) }
7
+ describe "#did_destroy" do
8
+ it "triggers a :destroy event on the record" do
9
+ called = false
10
+ model.on(:destroy) { called = true }
11
+ model.did_destroy
12
+ called.should eq(true)
13
+ end
14
+
15
+ it "triggers a :destroy event on the class" do
16
+ called = false
17
+ model_class.on(:destroy) { called = true }
18
+ model.did_destroy
19
+ called.should eq(true)
20
+ end
21
+
22
+ it "removes the record from the class identity_map" do
23
+ loaded_model.did_destroy
24
+ model_class.identity_map[loaded_model.id].should eq(nil)
25
+ end
26
+
27
+ it "removes the record from the class record_array" do
28
+ loaded_model.did_destroy
29
+ model_class.all.should_not include(loaded_model)
30
+ end
31
+ end
32
+
33
+ describe '#destroyed?' do
34
+ it 'is false for "living" models' do
35
+ model.destroyed?.should be_falsey
36
+ end
37
+
38
+ it "is true for destroyed models" do
39
+ loaded_model.did_destroy
40
+ loaded_model.destroyed?.should be_truthy
41
+ end
42
+ end
43
+
44
+ describe "#did_create" do
45
+ it "sets @new_record to false" do
46
+ model.did_create
47
+ model.new_record?.should eq(false)
48
+ end
49
+
50
+ it "adds record to class identity_map" do
51
+ model.id = 863
52
+ model.did_create
53
+ model.class.identity_map[863].should eq(model)
54
+ end
55
+
56
+ it "adds record to class record array" do
57
+ model.class.all.should == []
58
+ model.did_create
59
+ model.class.all.should == [model]
60
+ end
61
+
62
+ it "triggers a :create event on the record" do
63
+ called = false
64
+ model.on(:create) { called = true }
65
+ model.did_create
66
+ called.should eq(true)
67
+ end
68
+
69
+ it "triggers a :create event on the class" do
70
+ called = false
71
+ model.class.on(:create) { called = true }
72
+ model.did_create
73
+ called.should eq(true)
74
+ end
75
+ end
76
+
77
+ describe ".all" do
78
+ it "is a record array of all models" do
79
+ model.class.all.should == []
80
+ model.did_create
81
+ model.class.all.should == [model]
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vienna::Model do
4
+ describe ".new" do
5
+ it "should set @new_record to true" do
6
+ SimpleModel.new.new_record?.should eq(true)
7
+ end
8
+ end
9
+
10
+ describe ".primary_key" do
11
+ it "should have a default primary key" do
12
+ SimpleModel.primary_key.should eq(:id)
13
+ end
14
+
15
+ it "should be changeable" do
16
+ AdvancedModel.primary_key.should eq(:title)
17
+ end
18
+ end
19
+
20
+ describe ".load" do
21
+ it "raises an ArgumentError if no id present" do
22
+ lambda {
23
+ SimpleModel.load({})
24
+ }.should raise_error(ArgumentError)
25
+ end
26
+
27
+ it "should be able to load models with own primary_key" do
28
+ AdvancedModel.load(title: 100).should be_kind_of(AdvancedModel)
29
+ end
30
+
31
+ it "should set @new_record to false on the model" do
32
+ model = SimpleModel.load(id: 42)
33
+ model.new_record?.should eq(false)
34
+ end
35
+
36
+ it "should cache model" do
37
+ SimpleModel.identity_map[8].should be_nil
38
+ model = SimpleModel.load(id: 8)
39
+ SimpleModel.identity_map[8].should eq(model)
40
+ end
41
+
42
+ it "saves the model in .all record array" do
43
+ SimpleModel.all.should == []
44
+ model = SimpleModel.load(id: 10)
45
+ SimpleModel.all.should == [model]
46
+ end
47
+
48
+ it "should update existing models" do
49
+ foo = SimpleModel.load(id: 9, name: 'Adam')
50
+ bar = SimpleModel.load(id: 9, name: 'Beynon')
51
+ foo.should equal(bar)
52
+ foo.name.should eq("Beynon")
53
+ end
54
+ end
55
+
56
+ describe ".load_json" do
57
+ it "should load a model from native json/js object" do
58
+ obj = `{"id": 13, "name": "Bob"}`
59
+ model = SimpleModel.load_json obj
60
+ model.id.should eq(13)
61
+ model.name.should eq("Bob")
62
+ end
63
+ end
64
+
65
+ describe ".adapter" do
66
+ it "sets a new instance of the passed adapter as @adapter" do
67
+ klass = Class.new(Vienna::Model) do
68
+ adapter Vienna::Adapter
69
+ end
70
+
71
+ klass.instance_variable_get(:@adapter).should be_kind_of(Vienna::Adapter)
72
+ end
73
+
74
+ it "returns the adapter set on the model subclass" do
75
+ klass = Class.new(Vienna::Model) { adapter Vienna::Adapter }
76
+ klass.adapter.should be_kind_of(Vienna::Adapter)
77
+ end
78
+
79
+ it "raises an error when no adapter set on model subclass" do
80
+ klass = Class.new(Vienna::Model)
81
+ lambda { klass.adapter }.should raise_error(Exception)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+ require 'vienna/observable_array'
3
+
4
+ class ObservableArraySpec
5
+ include Vienna::ObservableArray
6
+ end
7
+
8
+ describe Vienna::ObservableArray do
9
+ let(:klass) { ObservableArraySpec }
10
+ let(:empty) { klass.new }
11
+ let(:foobar) { klass.new([:foo, :bar]) }
12
+
13
+ describe ".new" do
14
+ it "takes an optional content" do
15
+ klass.new.content.should == []
16
+ klass.new([1, 2, 3]).content.should == [1, 2, 3]
17
+ end
18
+ end
19
+
20
+ describe "#<<" do
21
+ it "pushes each object into the content" do
22
+ empty << :foo
23
+ empty << :bar
24
+ empty << :baz
25
+
26
+ empty.content.should == [:foo, :bar, :baz]
27
+ end
28
+
29
+ it "generates a change event for starting index and single added item" do
30
+ expect(empty).to receive(:array_content_did_change).once.with(0, 0, 1)
31
+ empty << :some_object
32
+
33
+ expect(foobar).to receive(:array_content_did_change).once.with(2, 0, 1)
34
+ foobar << :other_object
35
+ end
36
+ end
37
+
38
+ describe "#delete" do
39
+ it "deletes the object from the content array" do
40
+ foobar.delete :foo
41
+ foobar.content.should == [:bar]
42
+ end
43
+
44
+ it "notifies observers with single remove object" do
45
+ expect(foobar).to receive(:array_content_did_change).once.with(1, 1, 0)
46
+ foobar.delete :bar
47
+ end
48
+
49
+ it "has no effect when object not present" do
50
+ expect(foobar).to_not receive(:array_content_did_change)
51
+ foobar.delete :baz
52
+ end
53
+ end
54
+
55
+ describe "#insert" do
56
+ it "adds the object to the content array at specified index" do
57
+ empty.insert 0, :foo
58
+ empty.content.should == [:foo]
59
+
60
+ foobar.insert 1, :baz
61
+ foobar.content.should == [:foo, :baz, :bar]
62
+ end
63
+
64
+ it "notifies observers with single added object at index" do
65
+ expect(empty).to receive(:array_content_did_change).once.with(0, 0, 1)
66
+ empty.insert 0, :omg
67
+
68
+ expect(foobar).to receive(:array_content_did_change).once.with(1, 0, 1)
69
+ foobar.insert 1, :wow
70
+ end
71
+
72
+ it "raises an ArgumentError for index out of range" do
73
+ expect { empty.insert 2, :foo }.to raise_error(ArgumentError)
74
+ expect { foobar.insert 90, :foo }.to raise_error(ArgumentError)
75
+ end
76
+ end
77
+
78
+ describe "#clear" do
79
+ it "removes all items from the content array" do
80
+ empty.clear
81
+ empty.content.should == []
82
+
83
+ foobar.clear
84
+ foobar.content.should == []
85
+ end
86
+
87
+ it "notifies observers to remove all existing objects" do
88
+ expect(empty).to receive(:array_content_did_change).once.with(0, 0, 0)
89
+ empty.clear
90
+
91
+ expect(foobar).to receive(:array_content_did_change).once.with(0, 2, 0)
92
+ foobar.clear
93
+ end
94
+ end
95
+
96
+ describe "#array_content_did_change" do
97
+ it "triggers a :size attribute change" do
98
+ called = false
99
+ empty.add_observer(:size) { called = true }
100
+ empty.clear
101
+
102
+ called.should == true
103
+ end
104
+
105
+ it "triggers a :content attribute change" do
106
+ called = false
107
+ empty.add_observer(:content) { called = true }
108
+ empty.clear
109
+
110
+ called.should == true
111
+ end
112
+
113
+ it "triggers a :empty? attribute change" do
114
+ called = false
115
+ empty.add_observer(:empty?) { called = true }
116
+ empty.clear
117
+
118
+ called.should == true
119
+ end
120
+
121
+ it "notifies each observer added using add_array_observer" do
122
+ observer = double(:observer)
123
+ expect(observer).to receive(:array_did_change).once.with(empty, 0, 0, 0)
124
+
125
+ empty.add_array_observer observer
126
+
127
+ empty.clear
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'vienna/observable'
3
+
4
+ class ObservableSpec
5
+ include Vienna::Observable
6
+
7
+ attr_accessor :foo, :bar, :baz
8
+
9
+ def baz=(b)
10
+ @baz = b + 10
11
+ end
12
+
13
+ def bar=(b)
14
+ @bar = b
15
+ "#bar"
16
+ end
17
+ end
18
+
19
+ describe Vienna::Observable do
20
+
21
+ let(:object) { ObservableSpec.new }
22
+
23
+ describe "#replace_writer_for" do
24
+ it "still calls the original method using super" do
25
+ object.replace_writer_for(:foo)
26
+ object.baz = 100
27
+ object.baz.should eq(110)
28
+ end
29
+
30
+ it "does not add a setter unless an existing attribute= method exists" do
31
+ object.replace_writer_for(:bob)
32
+ object.should_not respond_to(:bob=)
33
+ end
34
+
35
+ it "the new writer calls attribute_did_change with attribute name" do
36
+ object.replace_writer_for(:foo)
37
+ def object.attribute_did_change(attribute); @_called = attribute; end
38
+
39
+ object.instance_variable_get(:@_called).should be_nil
40
+ object.foo = 100
41
+ object.instance_variable_get(:@_called).should eq(:foo)
42
+ end
43
+ end
44
+
45
+ describe "#add_observer" do
46
+ it "handlers can be added to observe specific attributes" do
47
+ count = 0
48
+ object.add_observer(:foo) { count += 1 }
49
+
50
+ object.foo = 100
51
+ count.should eq(1)
52
+
53
+ object.foo = 150
54
+ count.should eq(2)
55
+ end
56
+
57
+ it "allows more than one handler to be added for an attribute" do
58
+ result = []
59
+ object.add_observer(:foo) { result << :first }
60
+ object.add_observer(:foo) { result << :second }
61
+
62
+ object.foo = 42
63
+ result.should eq([:first, :second])
64
+
65
+ object.foo = 3.142
66
+ result.should eq([:first, :second, :first, :second])
67
+ end
68
+ end
69
+
70
+ describe "#attribute_did_change" do
71
+ it "does not break for an object with no observers" do
72
+ object.attribute_did_change(:foo_bar)
73
+ end
74
+
75
+ it "does not break when given an attriubte with no observers (but another observable exists)" do
76
+ object.add_observer(:foo) {}
77
+ object.attribute_did_change(:bar)
78
+ end
79
+
80
+ it "passes new value to each handler" do
81
+ result = nil
82
+ object.add_observer(:foo) { |val| result = val }
83
+
84
+ object.foo = 42
85
+ result.should eq(42)
86
+
87
+ object.foo = 3.142
88
+ result.should eq(3.142)
89
+ end
90
+ end
91
+
92
+ describe "#remove_observer" do
93
+ it "has no effect when no observers setup for attribute" do
94
+ object.remove_observer(:foo, proc {})
95
+ end
96
+
97
+ it "has no effect if the handler doesnt exist for attribute" do
98
+ p = proc {}
99
+ object.add_observer(:foo) {}
100
+ object.remove_observer(:foo, p)
101
+ end
102
+
103
+ it "removes an existing handler for given attribute" do
104
+ count = 0
105
+ handler = proc { count += 1 }
106
+ object.add_observer(:foo, &handler)
107
+
108
+ object.foo = 42
109
+ count.should eq(1)
110
+
111
+ object.remove_observer(:foo, handler)
112
+ object.foo = 49
113
+ count.should eq(1)
114
+ end
115
+ end
116
+ end