compositor 0.1.1 → 0.1.3

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