compositor 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.pairs CHANGED
@@ -7,6 +7,7 @@ pairs:
7
7
  es: Eric Saxby; sax
8
8
  cc: Cihan Cimen; cihan
9
9
  sc: Server Cimen; server
10
+ rm: Richard Millan; richardiux
10
11
  email:
11
12
  prefix: pair
12
13
  domain: wanelo.com
data/README.md CHANGED
@@ -24,30 +24,40 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- For each model that needs a hash/json representation you need to create a ruby class that subclasses Composite::Leaf,
28
- adds some custom state that's important for rendering that object, and implements #to_hash method:
27
+ For each model that needs a hash/json representation you need to create a ruby class that subclasses ```Composite::Leaf```,
28
+ adds some custom state that's important for rendering that object in addition to ```view_context```, and implement the ```#to_hash```
29
+ method.
30
+
31
+ The ```view_context``` variable is a reference to an object holding necessary helpers for generating JSON, for example
32
+ view_context is automatically available inside Rails controllers, and contains helper methods necessary to generate application URLs.
33
+ Outside of Rails application, ```view_context``` can be any other object holding application helpers or state. All
34
+ subclasses of ```Compositor::Leaf``` inherit view_context reference, and can use it to construct Hash representations.
35
+
36
+ We recommend you place your Compositor classes in eg ```app/compositors/*``` directory, that has one compositor
37
+ class per model class you will be rendering. Example below would be ```app/compositors/user.rb```, a compositor class
38
+ wrapping ```User``` model.
29
39
 
30
40
  ```ruby
31
- module Compositor
32
- class Leaf::User < ::Compositor::Leaf
33
- attr_accessor :user
34
-
35
- def initialize(view_context, user, attrs = {})
36
- super(view_context, {user: user}.merge!(attrs))
37
- end
38
-
39
- def to_hash
40
- with_root_element do
41
- {
42
- id: user.id,
43
- username: user.username,
44
- location: user.location,
45
- bio: user.bio,
46
- url: user.url
47
- }
48
- end
49
- end
50
- end
41
+ # The actual class name "User" is converted into a DSL method named "user", shown later.
42
+
43
+ class UserCompositor < Compositor::Leaf
44
+ attr_accessor :user
45
+
46
+ def initialize(context, user, attrs = {})
47
+ super(context, attrs)
48
+ self.user = user
49
+ end
50
+
51
+ def to_hash
52
+ {
53
+ id: user.id,
54
+ username: user.username,
55
+ location: user.location,
56
+ bio: user.bio,
57
+ url: user.url,
58
+ image_url: context.image_path(user.avatar),
59
+ ...
60
+ }
51
61
  end
52
62
  end
53
63
  ```
@@ -56,30 +66,34 @@ This small class automatically registers "user" DSL method, which receives a use
56
66
  important attributes.
57
67
 
58
68
  Then this class can be merged with other similar "leaf" classes, or another "composite" class, such as
59
- Composite::Hash or Composite::List to create a complex nested Hash or JSON data structure.
69
+ Composite::Map or Composite::List to create a Hash or an Array as the top-level JSON data structure.
60
70
 
61
71
  Once the tree of composite objects has been setup, calling #to_hash on the top level object quickly
62
72
  generates hash by walking the tree and merging everything together.
63
73
 
74
+ In the example below, application defines also ```StoreCompositor```, ```ProductCompositor``` classes
75
+ that similar to ```UserCompositor``` return hash representations of each model object.
76
+
64
77
  ```ruby
65
78
 
66
- composite = Composite.create(view_context) do
67
- hash do
68
- store store, root: :store
69
- user current_user, root: :user
70
- list collection: products, root: :products do |p|
79
+ compositor = Compositor::DSL.create(context) do
80
+ map do
81
+ store @store, root: :store
82
+ user @user, root: :user
83
+ list collection: @products, root: :products do |p|
71
84
  product p
72
85
  end
73
86
  end
74
87
  end
75
88
 
76
- puts composite.to_hash # =>
89
+ puts compositor.to_hash # =>
77
90
 
78
91
  {
79
92
  :store => {
80
93
  id: 12354,
81
94
  name: "amazon.com",
82
95
  url: "http://www.amazon.com",
96
+
83
97
  ..
84
98
  },
85
99
  :user => {
@@ -87,7 +101,8 @@ generates hash by walking the tree and merging everything together.
87
101
  username: "kigster",
88
102
  location: "San Francisco",
89
103
  bio: "",
90
- url: ""
104
+ url: "",
105
+ image_url: "http://cdn-app.domain.com/kigster/avatar/200.jpg"
91
106
  },
92
107
  :products => {
93
108
  [ id: 1234, :name => "Awesome Product", ... ],
@@ -96,6 +111,10 @@ generates hash by walking the tree and merging everything together.
96
111
  }
97
112
  ```
98
113
 
114
+ The context is an object that can contain helpers, instance variables, or anything that can be used
115
+ within leaves. For example, you can pass in the view_context from the controller to get access to any
116
+ Rails routes or helpers.
117
+
99
118
  ## Contributing
100
119
 
101
120
  1. Fork it
@@ -15,6 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = %w(lib)
16
16
  gem.version = Compositor::VERSION
17
17
 
18
+ gem.add_dependency 'oj'
19
+
18
20
  gem.add_development_dependency 'rspec'
19
21
 
20
22
  gem.add_development_dependency 'guard-rspec'
@@ -3,22 +3,28 @@ require 'compositor/version'
3
3
  module Compositor
4
4
  end
5
5
 
6
- class String
7
- def constantize
8
- camel_cased_word = self
9
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
10
- raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
11
- end
6
+ unless "".respond_to?(:constantize)
7
+ class String
8
+ def constantize
9
+ camel_cased_word = self
10
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
11
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
12
+ end
12
13
 
13
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
14
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
15
+ end
14
16
  end
17
+ end
15
18
 
16
- def underscore
17
- self.gsub(/::/, '/').
19
+ unless "".respond_to?(:underscore)
20
+ class String
21
+ def underscore
22
+ self.gsub(/::/, '/').
18
23
  gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
19
24
  gsub(/([a-z\d])([A-Z])/, '\1_\2').
20
25
  tr("-", "_").
21
26
  downcase
27
+ end
22
28
  end
23
29
  end
24
30
 
@@ -1,11 +1,11 @@
1
1
  module Compositor
2
2
  class Base
3
3
  attr_reader :attrs
4
- attr_accessor :root, :view_context
4
+ attr_accessor :root, :context
5
5
 
6
6
  def initialize(view_context, attrs = {})
7
7
  @attrs = attrs
8
- self.view_context = view_context
8
+ self.context = view_context
9
9
  attrs.each_pair do |key, value|
10
10
  self.send("#{key}=", value)
11
11
  end
@@ -23,10 +23,6 @@ module Compositor
23
23
  to_hash
24
24
  end
25
25
 
26
- def collection_to_generator(klazz, collection)
27
- collection.map { |o| klazz.new(view_context) }
28
- end
29
-
30
26
  def to_json(options = {})
31
27
  Oj.dump(to_hash)
32
28
  end
@@ -40,13 +36,29 @@ module Compositor
40
36
  end
41
37
 
42
38
  def self.root_class_name(klazz)
43
- klazz.name.gsub(/.*::/, '').underscore
39
+ klazz.name.gsub(/(.*::)|(Compositor$)/, '').underscore
40
+ end
41
+
42
+ def self.inherited(subclass)
43
+ method_name = root_class_name(subclass)
44
+ unless method_name.eql?("base") # check if it's already defined
45
+ Compositor::DSL.send(:define_method, method_name) do |*args, &block|
46
+ subclass.
47
+ new(@context, *args).
48
+ dsl(self, &block)
49
+ end
50
+ end
51
+ end
52
+
53
+ def dsl
54
+ raise "Implement in subclasses"
44
55
  end
45
56
  end
46
57
  end
47
58
 
48
- require_relative 'leaf'
49
- require_relative 'composite'
50
59
  require_relative 'dsl'
60
+ require_relative 'composite'
61
+ require_relative 'leaf'
62
+ require_relative 'literal'
51
63
  require_relative 'list'
52
- require_relative 'hash'
64
+ require_relative 'map'
@@ -2,8 +2,9 @@ module Compositor
2
2
  class Composite < Compositor::Base
3
3
  attr_accessor :collection, :renderer
4
4
 
5
- def initialize(view_context, *args)
5
+ def initialize(view_context, args = {})
6
6
  super
7
+ @collection_set = true if args.has_key?(:collection)
7
8
  self.collection ||= []
8
9
  end
9
10
 
@@ -13,41 +14,29 @@ module Compositor
13
14
  end
14
15
  end
15
16
 
16
- def map_collection
17
- self.collection = self.collection.map do |item|
18
- yield item
19
- end
20
- end
21
-
22
17
  def composite?
23
18
  true
24
19
  end
25
20
 
26
- def self.inherited(subclass)
27
- method_name = subclass.name.gsub(/.*::/, '').underscore
28
- unless method_name.eql?("base")
29
- Compositor::DSL.send(:define_method, method_name) do |args = {}, &block|
30
- original_generator = self.generator
31
- composite = subclass.new(self.view_context, args)
32
-
33
- self.generator = composite
34
-
35
- if args[:collection] && block
36
- # reset collection, we'll be mapping it via a block
37
- composite.collection = []
38
- args[:collection].each do |object|
39
- self.instance_exec(object, &block)
40
- end
41
- elsif block
42
- self.instance_eval &block
43
- end
44
-
45
- if original_generator
46
- self.generator = original_generator
47
- self.generator.collection << composite
48
- end
21
+ def dsl(dsl, &block)
22
+ original_generator = dsl.generator
23
+
24
+ dsl.generator = self
25
+
26
+ if self.collection && @collection_set && block
27
+ # reset collection, we'll be mapping it via a block
28
+ unmapped_collection = collection
29
+ self.collection = []
30
+ unmapped_collection.each do |object|
31
+ dsl.instance_exec(object, &block)
49
32
  end
33
+ elsif block
34
+ dsl.instance_eval &block
50
35
  end
36
+
37
+ dsl.generator = original_generator if original_generator
38
+
39
+ dsl.generator.collection << self if dsl.generator != self
51
40
  end
52
41
  end
53
42
  end
@@ -1,26 +1,23 @@
1
1
  module Compositor
2
2
  class DSL
3
- attr_reader :view_context
4
- attr_accessor :result, :generator
3
+ attr_reader :context
4
+ attr_accessor :generator
5
5
 
6
- def initialize(view_context)
7
- @view_context = view_context
6
+ def initialize(context)
7
+ @context = context
8
8
  end
9
9
 
10
- def self.create(view_context, &block)
11
- dsl = new(view_context)
10
+ def self.create(context, &block)
11
+ dsl = new(context)
12
+ context.instance_variables.each do |variable|
13
+ dsl.instance_variable_set(variable, context.instance_variable_get(variable))
14
+ end
12
15
  dsl.instance_eval &block if block
13
16
  dsl
14
17
  end
15
18
 
16
- def paginate collection, params
17
- paginator collection: collection,
18
- pagination_url: params[:pagination_url],
19
- params: params[:api_params]
20
- end
21
-
22
- def to_json
23
- generator.to_json
19
+ def to_json(options = {})
20
+ generator.to_json(options)
24
21
  end
25
22
 
26
23
  def to_hash
@@ -1,14 +1,5 @@
1
1
  module Compositor
2
2
  class Leaf < Compositor::Base
3
- attr_accessor :object
4
-
5
- def initialize(view_context, object = {}, args = {})
6
- if object.is_a?(::Hash)
7
- super(view_context, object)
8
- else
9
- super(view_context, {object: object}.merge!(args))
10
- end
11
- end
12
3
 
13
4
  def root
14
5
  if @root.is_a?(Symbol)
@@ -24,19 +15,12 @@ module Compositor
24
15
  false
25
16
  end
26
17
 
27
- def self.inherited(subclass)
28
- method_name = root_class_name(subclass)
29
- unless method_name.eql?("base")
30
- Compositor::DSL.send(:define_method, method_name) do |*args|
31
- leaf = subclass.new(@view_context, *args)
32
- if self.generator
33
- raise "Leaves should be called within composite" unless self.generator.composite?
34
- self.generator.collection << leaf
35
- else
36
- self.generator = leaf
37
- end
38
- leaf
39
- end
18
+ def dsl(dsl)
19
+ if dsl.generator
20
+ raise "Leaves should be called within composite" unless dsl.generator.composite?
21
+ dsl.generator.collection << self
22
+ else
23
+ dsl.generator = self
40
24
  end
41
25
  end
42
26
  end
@@ -0,0 +1,14 @@
1
+ module Compositor
2
+ class Literal < Compositor::Leaf
3
+ attr_accessor :object
4
+
5
+ def initialize(view_context, object = {}, args = {})
6
+ super(view_context, args)
7
+ self.object = object
8
+ end
9
+
10
+ def to_hash
11
+ object
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  module Compositor
2
- class Hash < ::Compositor::Composite
2
+ class Map < ::Compositor::Composite
3
3
  def renderer
4
4
  @renderer ||= Compositor::Renderer::Merged
5
5
  end
@@ -1,3 +1,3 @@
1
1
  module Compositor
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::Base do
4
+ describe "#root_class_name" do
5
+ it "returns the underscored class name" do
6
+ Compositor::Base.root_class_name(Object).should == "object"
7
+ end
8
+
9
+ it "returns the underscored class name with compositor stripped out" do
10
+ Compositor::Base.root_class_name(DslStringCompositor).should == "dsl_string"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::DSL do
4
+
5
+ let(:context) { Object.new }
6
+
7
+ describe '#empty' do
8
+ it 'returns the default type' do
9
+ dsl = Compositor::DSL.create(context) do
10
+ end
11
+
12
+ nil.should == dsl.to_hash
13
+ end
14
+ end
15
+
16
+ describe 'instance variables' do
17
+ it 'allows instance variables from the view context to be accessed in the dsl evaluation' do
18
+ context.instance_eval do
19
+ @blah = 1
20
+ end
21
+
22
+ Compositor::DSL.create(context) do
23
+ raise "Instance variable should be available in DSL" unless @blah == 1
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::Map do
4
+ let(:context) { Object.new }
5
+
6
+ it 'returns the generated map' do
7
+ expected = {
8
+ tests: {
9
+ num1: {number: 1},
10
+ num2: {number: 2},
11
+ num3: {number: 3}
12
+ }
13
+ }
14
+
15
+ dsl = Compositor::DSL.create(context)
16
+ dsl.map root: :tests do
17
+ dsl.dsl_int 1, root: :num1
18
+ dsl.dsl_int 2, root: :num2
19
+ dsl.dsl_int 3, root: :num3
20
+ end
21
+
22
+ expected.should == dsl.to_hash
23
+ end
24
+
25
+ it 'returns the generated deeply nested map without explicit receiver' do
26
+ expected = {
27
+ tests: {
28
+ num1: {number: 1},
29
+ num2: {number: 2},
30
+ num3: {number: 3},
31
+ stuff: [
32
+ {number: 10},
33
+ {number: 11}
34
+ ]
35
+ }
36
+ }
37
+
38
+ dsl = Compositor::DSL.create(context)
39
+ dsl.map root: :tests do
40
+ dsl_int 1, root: :num1
41
+ dsl_int 2, root: :num2
42
+ dsl_int 3, root: :num3
43
+ list :root => :stuff do
44
+ dsl_int 10
45
+ dsl_int 11
46
+ end
47
+ end
48
+
49
+ expected.should == dsl.to_hash
50
+ end
51
+
52
+ describe '#empty' do
53
+ it 'returns the default type' do
54
+ dsl = Compositor::DSL.create(context) do
55
+ map collection: [], root: false
56
+ end
57
+
58
+ {}.should == dsl.to_hash
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::Leaf do
4
+ let(:context) { Object.new }
5
+
6
+ describe '#create' do
7
+ it "defines #dsl_string method on the DSL class" do
8
+ dsl = Compositor::DSL.create(context)
9
+ dsl.should respond_to(:dsl_string)
10
+ end
11
+
12
+ it "allows calling defined methods via a block" do
13
+ block_ran = false
14
+ Compositor::DSL.create(context) do |dsl|
15
+ dsl.dsl_string
16
+ block_ran = true
17
+ end
18
+ block_ran.should be_true
19
+ end
20
+
21
+ it "returns last generator called via block" do
22
+ dsl = Compositor::DSL.create(context) do |dsl|
23
+ dsl.dsl_string
24
+ end
25
+
26
+ {a: "b"}.should == dsl.to_hash
27
+ end
28
+
29
+ it "returns an instance of subclass" do
30
+ dsl = Compositor::DSL.create(context).dsl_string
31
+ dsl.should be_kind_of(DslStringCompositor)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::List do
4
+ let(:context) { Object.new }
5
+
6
+ it 'returns the generated array with the explicit receiver' do
7
+ integers = [1, 2, 3]
8
+ expected = {
9
+ tests: [
10
+ {number: 1},
11
+ {number: 2},
12
+ {number: 3}
13
+ ]
14
+ }
15
+
16
+ dsl = Compositor::DSL.create(context)
17
+ dsl.list root: :tests, collection: integers do |item|
18
+ dsl.dsl_int item
19
+ end
20
+
21
+ dsl.to_hash.should == expected
22
+ end
23
+
24
+ it 'returns the generated array with explicit receiver' do
25
+ integers = [1, 2, 3]
26
+ expected = {
27
+ tests: [
28
+ {number: 1},
29
+ {number: 2},
30
+ {number: 3}
31
+ ]
32
+ }
33
+
34
+ dsl = Compositor::DSL.create(context)
35
+ dsl.list root: :tests, collection: integers do |item|
36
+ dsl_int item
37
+ end
38
+
39
+ expected.should == dsl.to_hash
40
+ end
41
+
42
+ describe '#empty' do
43
+ it 'returns the default type' do
44
+ dsl = Compositor::DSL.create(context) do
45
+ list collection: [], root: false
46
+ end
47
+
48
+ [].should == dsl.to_hash
49
+ end
50
+
51
+ it 'doesnt execute the block if an empty collection is passed' do
52
+ dsl = Compositor::DSL.create(context) do
53
+ list collection: [], root: false do |p|
54
+ raise "Shouldnt be a DSL" if p.instance_of?(Compositor::DSL)
55
+ end
56
+ end
57
+
58
+ [].should == dsl.to_hash
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compositor::Literal do
4
+
5
+ let(:context) { Object.new }
6
+
7
+ it 'returns the hash its given' do
8
+ actual = { test: 123 }
9
+
10
+ Compositor::Literal.new(context, actual).to_hash.should == actual
11
+ end
12
+ end
@@ -1,8 +1,8 @@
1
- require_relative '../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Performance' do
4
4
 
5
- let(:view_context) { Object.new }
5
+ let(:context) { Object.new }
6
6
  let(:permitted_dsl_performance_penalty) { 60 } # 60% slower is allowed, any slower is not.)
7
7
 
8
8
  describe 'generating DSL' do
@@ -15,9 +15,9 @@ describe 'Performance' do
15
15
  dsl = nil
16
16
  output = Benchmark.measure do
17
17
  10000.times do
18
- dsl = Compositor::DSL.create(view_context) do |dsl|
19
- hash do
20
- dsl_string "hello"
18
+ dsl = Compositor::DSL.create(context) do |dsl|
19
+ map do
20
+ dsl_string string: "hello"
21
21
  dsl_int 3
22
22
  list collection: [1, 2, 3], root: :numbers do |number|
23
23
  dsl_int number
@@ -30,15 +30,14 @@ describe 'Performance' do
30
30
 
31
31
  @timing[:dsl] = output.to_s.to_f
32
32
 
33
- cmp = nil
34
33
  output = Benchmark.measure do
35
34
  10000.times do
36
- string = Compositor::Leaf::DslString.new(view_context)
37
- int = Compositor::Leaf::DslInt.new(view_context, 3)
38
- list = Compositor::List.new(view_context,
35
+ string = DslStringCompositor.new(context)
36
+ int = DslIntCompositor.new(context, 3)
37
+ list = Compositor::List.new(context,
39
38
  root: :numbers,
40
- collection: [1, 2, 3].map! { |n| Compositor::Leaf::DslInt.new(view_context, n) })
41
- cmp = Compositor::Hash.new(view_context, collection: [string, int, list])
39
+ collection: [1, 2, 3].map! { |n| DslIntCompositor.new(context, n) })
40
+ cmp = Compositor::Map.new(context, collection: [string, int, list])
42
41
  cmp.to_hash.should == {:a => "b", :number => 3, :numbers => [{:number => 1}, {:number => 2}, {:number => 3}]}
43
42
  end
44
43
  end
@@ -1,33 +1,35 @@
1
- module Compositor
2
- class Leaf::DslString < Compositor::Leaf
3
- def to_hash
4
- {
5
- a: "b"
6
- }
7
- end
8
- end
1
+ class DslStringCompositor < Compositor::Leaf
2
+ attr_accessor :string
9
3
 
10
- class Leaf::DslInt < Compositor::Leaf
11
- attr_accessor :number
4
+ def to_hash
5
+ {
6
+ a: "b"
7
+ }
8
+ end
9
+ end
12
10
 
13
- def initialize(view_context, number, attrs = {})
14
- super(view_context, {number: number}.merge!(attrs))
15
- end
11
+ class DslIntCompositor < Compositor::Leaf
12
+ attr_accessor :number
16
13
 
17
- def to_hash
18
- with_root_element do
19
- {
20
- number: @number
21
- }
22
- end
23
- end
14
+ def initialize(view_context, number, attrs = {})
15
+ super(view_context, {number: number}.merge!(attrs))
24
16
  end
25
17
 
26
- class Leaf::DslObject < Compositor::Leaf
27
- def to_hash
18
+ def to_hash
19
+ with_root_element do
28
20
  {
29
- a: object
21
+ number: @number
30
22
  }
31
23
  end
32
24
  end
33
25
  end
26
+
27
+ class DslObjectCompositor < Compositor::Leaf
28
+ attr_accessor :object
29
+
30
+ def to_hash
31
+ {
32
+ a: object
33
+ }
34
+ end
35
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compositor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,8 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-05-29 00:00:00.000000000 Z
13
+ date: 2013-05-31 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: oj
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
15
31
  - !ruby/object:Gem::Dependency
16
32
  name: rspec
17
33
  requirement: !ruby/object:Gem::Requirement
@@ -83,14 +99,20 @@ files:
83
99
  - lib/compositor/base.rb
84
100
  - lib/compositor/composite.rb
85
101
  - lib/compositor/dsl.rb
86
- - lib/compositor/hash.rb
87
102
  - lib/compositor/leaf.rb
88
103
  - lib/compositor/list.rb
104
+ - lib/compositor/literal.rb
105
+ - lib/compositor/map.rb
89
106
  - lib/compositor/renderer/base.rb
90
107
  - lib/compositor/renderer/iterator.rb
91
108
  - lib/compositor/renderer/merged.rb
92
109
  - lib/compositor/version.rb
93
- - spec/compositor/compositor_spec.rb
110
+ - spec/compositor/base_spec.rb
111
+ - spec/compositor/dsl_spec.rb
112
+ - spec/compositor/hash_spec.rb
113
+ - spec/compositor/leaf_spec.rb
114
+ - spec/compositor/list_spec.rb
115
+ - spec/compositor/literal_spec.rb
94
116
  - spec/compositor/performance_spec.rb
95
117
  - spec/spec_helper.rb
96
118
  - spec/support/sample_dsl.rb
@@ -114,14 +136,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
136
  version: '0'
115
137
  requirements: []
116
138
  rubyforge_project:
117
- rubygems_version: 1.8.24
139
+ rubygems_version: 1.8.25
118
140
  signing_key:
119
141
  specification_version: 3
120
142
  summary: Composite design pattern with a convenient DSL for building JSON/Hashes of
121
143
  complex objects
122
144
  test_files:
123
- - spec/compositor/compositor_spec.rb
145
+ - spec/compositor/base_spec.rb
146
+ - spec/compositor/dsl_spec.rb
147
+ - spec/compositor/hash_spec.rb
148
+ - spec/compositor/leaf_spec.rb
149
+ - spec/compositor/list_spec.rb
150
+ - spec/compositor/literal_spec.rb
124
151
  - spec/compositor/performance_spec.rb
125
152
  - spec/spec_helper.rb
126
153
  - spec/support/sample_dsl.rb
127
- has_rdoc:
@@ -1,168 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe Compositor::DSL do
4
-
5
- let(:view_context) { Object.new }
6
-
7
- describe '#create' do
8
- it "defines #dsl_string method on the DSL class" do
9
- dsl = Compositor::DSL.create(view_context)
10
- dsl.should respond_to(:dsl_string)
11
- end
12
-
13
- it "allows calling defined methods via a block" do
14
- block_ran = false
15
- Compositor::DSL.create(view_context) do |dsl|
16
- dsl.dsl_string
17
- block_ran = true
18
- end
19
- block_ran.should be_true
20
- end
21
-
22
- it "returns last generator called via block" do
23
- dsl = Compositor::DSL.create(view_context) do |dsl|
24
- dsl.dsl_string
25
- end
26
-
27
- {a: "b"}.should == dsl.to_hash
28
- end
29
-
30
- it "returns an instance of subclass" do
31
- dsl = Compositor::DSL.create(view_context).dsl_string
32
- dsl.should be_kind_of(Compositor::Leaf::DslString)
33
- end
34
- end
35
-
36
- describe '#composite' do
37
- it 'returns the generated array with the explicit receiver' do
38
- integers = [1, 2, 3]
39
- expected = {
40
- tests: [
41
- {number: 1},
42
- {number: 2},
43
- {number: 3}
44
- ]
45
- }
46
-
47
- dsl = Compositor::DSL.create(view_context)
48
- dsl.list root: :tests, collection: integers do |item|
49
- dsl.dsl_int item
50
- end
51
-
52
- dsl.to_hash.should == expected
53
- end
54
-
55
- it 'returns the generated hash' do
56
- expected = {
57
- tests: {
58
- num1: {number: 1},
59
- num2: {number: 2},
60
- num3: {number: 3}
61
- }
62
- }
63
-
64
- dsl = Compositor::DSL.create(view_context)
65
- dsl.hash root: :tests do
66
- dsl.dsl_int 1, root: :num1
67
- dsl.dsl_int 2, root: :num2
68
- dsl.dsl_int 3, root: :num3
69
- end
70
-
71
- expected.should == dsl.to_hash
72
- end
73
-
74
- it 'returns the generated deeply nested hash' do
75
- expected = {
76
- tests: {
77
- num1: {number: 1},
78
- num2: {number: 2},
79
- num3: {number: 3},
80
- stuff: [
81
- {number: 10},
82
- {number: 11}
83
- ]
84
- }
85
- }
86
-
87
- dsl = Compositor::DSL.create(view_context)
88
- dsl.hash root: :tests do
89
- dsl.dsl_int 1, root: :num1
90
- dsl.dsl_int 2, root: :num2
91
- dsl.dsl_int 3, root: :num3
92
- dsl.list :root => :stuff do
93
- dsl.dsl_int 10
94
- dsl.dsl_int 11
95
- end
96
- end
97
-
98
- expected.should == dsl.to_hash
99
- end
100
-
101
- it 'returns the generated deeply nested hash without explicit receiver' do
102
- expected = {
103
- tests: {
104
- num1: {number: 1},
105
- num2: {number: 2},
106
- num3: {number: 3},
107
- stuff: [
108
- {number: 10},
109
- {number: 11}
110
- ]
111
- }
112
- }
113
-
114
- dsl = Compositor::DSL.create(view_context)
115
- dsl.hash root: :tests do
116
- dsl_int 1, root: :num1
117
- dsl_int 2, root: :num2
118
- dsl_int 3, root: :num3
119
- list :root => :stuff do
120
- dsl_int 10
121
- dsl_int 11
122
- end
123
- end
124
-
125
- expected.should == dsl.to_hash
126
- end
127
-
128
- it 'returns the generated array with explicit receiver' do
129
- integers = [1, 2, 3]
130
- expected = {
131
- tests: [
132
- {number: 1},
133
- {number: 2},
134
- {number: 3}
135
- ]
136
- }
137
-
138
- dsl = Compositor::DSL.create(view_context)
139
- dsl.list root: :tests, collection: integers do |item|
140
- dsl_int item
141
- end
142
-
143
- expected.should == dsl.to_hash
144
- end
145
- end
146
-
147
- describe '#empty' do
148
- it 'returns the default type' do
149
- dsl = Compositor::DSL.create(view_context) do
150
- end
151
-
152
- nil.should == dsl.to_hash
153
-
154
- dsl = Compositor::DSL.create(view_context) do
155
- hash collection: [], root: false
156
- end
157
-
158
- {}.should == dsl.to_hash
159
-
160
- dsl = Compositor::DSL.create(view_context) do
161
- list collection: [], root: false
162
- end
163
-
164
- [].should == dsl.to_hash
165
-
166
- end
167
- end
168
- end