opal-vienna 0.7.0

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 (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