compositor 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .idea
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.pairs ADDED
@@ -0,0 +1,12 @@
1
+ pairs:
2
+ ag: Atasay Gokkaya; atasay
3
+ km: Kaan Meralan; kaan
4
+ kg: Konstantin Gredeskoul; kig
5
+ ph: Paul Henry; paul
6
+ sf: Sean Flannagan; sean
7
+ es: Eric Saxby; sax
8
+ cc: Cihan Cimen; cihan
9
+ sc: Server Cimen; server
10
+ email:
11
+ prefix: pair
12
+ domain: wanelo.com
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ script: "bundle exec rspec"
5
+ notifications:
6
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spanx.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ #^syntax detection
3
+
4
+ # A sample Guardfile
5
+ # More info at https://github.com/guard/guard#readme
6
+
7
+ guard 'rspec' do
8
+ watch(%r{^compositor\.gemspec}) { "spec"}
9
+ watch(%r{^spec/.+_spec\.rb$})
10
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
11
+ watch('spec/spec_helper.rb') { "spec" }
12
+ end
13
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Wanelo, Inc
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ Compositor
2
+ =====
3
+
4
+ [![Build status](https://secure.travis-ci.org/wanelo/compositor.png)](http://travis-ci.org/wanelo/compositor)
5
+
6
+ Composite pattern with a neat DSL for constructing trees of objects in order to render them as a Hash, and subsequently
7
+ JSON. Used by Wanelo to generate all JSON API responses by compositing multiple objects together, converting to
8
+ a hash and then JSON.
9
+
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'compositor'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install compositor
24
+
25
+ ## Usage
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:
29
+
30
+ ```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
51
+ end
52
+ end
53
+ ```
54
+
55
+ This small class automatically registers "user" DSL method, which receives a user object and any other
56
+ important attributes.
57
+
58
+ 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.
60
+
61
+ Once the tree of composite objects has been setup, calling #to_hash on the top level object quickly
62
+ generates hash by walking the tree and merging everything together.
63
+
64
+ ```ruby
65
+
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|
71
+ product p
72
+ end
73
+ end
74
+ end
75
+
76
+ puts composite.to_hash # =>
77
+
78
+ {
79
+ :store => {
80
+ id: 12354,
81
+ name: "amazon.com",
82
+ url: "http://www.amazon.com",
83
+ ..
84
+ },
85
+ :user => {
86
+ id: 1234,
87
+ username: "kigster",
88
+ location: "San Francisco",
89
+ bio: "",
90
+ url: ""
91
+ },
92
+ :products => {
93
+ [ id: 1234, :name => "Awesome Product", ... ],
94
+ [ id: 4325, :name => "Another Awesome Product", ... ]
95
+ }
96
+ }
97
+ ```
98
+
99
+ ## Contributing
100
+
101
+ 1. Fork it
102
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
103
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
104
+ 4. Push to the branch (`git push origin my-new-feature`)
105
+ 5. Create new Pull Request
106
+
107
+ ## Maintainers
108
+
109
+ Konstantin Gredeskoul (@kigster) and Paul Henry (@letuboy)
110
+
111
+ (c) 2013, All rights reserved, distributed under MIT license.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/compositor/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Konstantin Gredeskoul","Paul Henry"]
6
+ gem.email = %w(kigster@gmail.com paul@wanelo.com)
7
+ gem.description = %q{Composite design pattern with a convenient DSL for building JSON/Hashes of complex objects}
8
+ gem.summary = %q{Composite design pattern with a convenient DSL for building JSON/Hashes of complex objects}
9
+ gem.homepage = "https://github.com/wanelo/compositor"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "compositor"
15
+ gem.require_paths = %w(lib)
16
+ gem.version = Compositor::VERSION
17
+
18
+ gem.add_development_dependency 'rspec'
19
+
20
+ gem.add_development_dependency 'guard-rspec'
21
+ gem.add_development_dependency 'rb-fsevent'
22
+ end
data/lib/compositor.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'compositor/version'
2
+
3
+ module Compositor
4
+ end
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
12
+
13
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
14
+ end
15
+
16
+ def underscore
17
+ self.gsub(/::/, '/').
18
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
19
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
20
+ tr("-", "_").
21
+ downcase
22
+ end
23
+ end
24
+
25
+ require_relative 'compositor/base'
26
+ require_relative 'compositor/renderer/base'
@@ -0,0 +1,52 @@
1
+ module Compositor
2
+ class Base
3
+ attr_reader :attrs
4
+ attr_accessor :root, :view_context
5
+
6
+ def initialize(view_context, attrs = {})
7
+ @attrs = attrs
8
+ self.view_context = view_context
9
+ attrs.each_pair do |key, value|
10
+ self.send("#{key}=", value)
11
+ end
12
+ end
13
+
14
+ def to_hash
15
+ raise NotImplementedError.new("Abstract method, should be implemented by subclasses")
16
+ end
17
+
18
+ def with_root_element
19
+ include_root? ? {root => yield} : yield
20
+ end
21
+
22
+ def to_h
23
+ to_hash
24
+ end
25
+
26
+ def collection_to_generator(klazz, collection)
27
+ collection.map { |o| klazz.new(view_context) }
28
+ end
29
+
30
+ def to_json(options = {})
31
+ Oj.dump(to_hash)
32
+ end
33
+
34
+ def include_root?
35
+ self.root ? true : false
36
+ end
37
+
38
+ def root_class_name
39
+ self.class.root_class_name(self.class)
40
+ end
41
+
42
+ def self.root_class_name(klazz)
43
+ klazz.name.gsub(/.*::/, '').underscore
44
+ end
45
+ end
46
+ end
47
+
48
+ require_relative 'leaf'
49
+ require_relative 'composite'
50
+ require_relative 'dsl'
51
+ require_relative 'list'
52
+ require_relative 'hash'
@@ -0,0 +1,53 @@
1
+ module Compositor
2
+ class Composite < Compositor::Base
3
+ attr_accessor :collection, :renderer
4
+
5
+ def initialize(view_context, *args)
6
+ super
7
+ self.collection ||= []
8
+ end
9
+
10
+ def to_hash
11
+ with_root_element do
12
+ renderer.new(self, collection).render
13
+ end
14
+ end
15
+
16
+ def map_collection
17
+ self.collection = self.collection.map do |item|
18
+ yield item
19
+ end
20
+ end
21
+
22
+ def composite?
23
+ true
24
+ end
25
+
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
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ module Compositor
2
+ class DSL
3
+ attr_reader :view_context
4
+ attr_accessor :result, :generator
5
+
6
+ def initialize(view_context)
7
+ @view_context = view_context
8
+ end
9
+
10
+ def self.create(view_context, &block)
11
+ dsl = new(view_context)
12
+ dsl.instance_eval &block if block
13
+ dsl
14
+ end
15
+
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
24
+ end
25
+
26
+ def to_hash
27
+ if generator
28
+ generator.to_hash
29
+ else
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,7 @@
1
+ module Compositor
2
+ class Hash < ::Compositor::Composite
3
+ def renderer
4
+ @renderer ||= Compositor::Renderer::Merged
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,43 @@
1
+ module Compositor
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
+
13
+ def root
14
+ if @root.is_a?(Symbol)
15
+ super
16
+ elsif @root
17
+ root_class_name.to_sym
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def composite?
24
+ false
25
+ end
26
+
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
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module Compositor
2
+ class List < Compositor::Composite
3
+ def renderer
4
+ @renderer ||= Compositor::Renderer::Iterator
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Compositor
2
+ module Renderer
3
+ class Base
4
+ attr_reader :composite, :collection
5
+
6
+ def initialize(composite, collection)
7
+ @composite = composite
8
+ @collection = collection
9
+ end
10
+
11
+ def render
12
+ raise NoMethodError.new "Define render() method in subclasses!"
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ require_relative 'iterator'
19
+ require_relative 'merged'
@@ -0,0 +1,9 @@
1
+ module Compositor
2
+ module Renderer
3
+ class Iterator < Base
4
+ def render
5
+ collection.inject([]) { |memo, item| memo << item.to_hash; memo }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Compositor
2
+ module Renderer
3
+ class Merged < Base
4
+ def render
5
+ return {} if collection.nil? or collection.size == 0
6
+ return collection.first.to_hash if collection.length == 1
7
+ collection.inject({}) do |result, hash|
8
+ result.merge!(hash.to_hash)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Compositor
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,168 @@
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
@@ -0,0 +1,52 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe 'Performance' do
4
+
5
+ let(:view_context) { Object.new }
6
+ let(:permitted_dsl_performance_penalty) { 60 } # 60% slower is allowed, any slower is not.)
7
+
8
+ describe 'generating DSL' do
9
+ before do
10
+ require 'benchmark'
11
+ @timing = { }
12
+ end
13
+
14
+ it "is no more than 60% slower than non-DSL" do
15
+ dsl = nil
16
+ output = Benchmark.measure do
17
+ 10000.times do
18
+ dsl = Compositor::DSL.create(view_context) do |dsl|
19
+ hash do
20
+ dsl_string "hello"
21
+ dsl_int 3
22
+ list collection: [1, 2, 3], root: :numbers do |number|
23
+ dsl_int number
24
+ end
25
+ end
26
+ end
27
+ dsl.to_hash.should == {:a => "b", :number => 3, :numbers => [{:number => 1}, {:number => 2}, {:number => 3}]}
28
+ end
29
+ end
30
+
31
+ @timing[:dsl] = output.to_s.to_f
32
+
33
+ cmp = nil
34
+ output = Benchmark.measure do
35
+ 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,
39
+ 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])
42
+ cmp.to_hash.should == {:a => "b", :number => 3, :numbers => [{:number => 1}, {:number => 2}, {:number => 3}]}
43
+ end
44
+ end
45
+
46
+ @timing[:nodsl] = output.to_s.to_f
47
+
48
+ difference = (100 * (@timing[:dsl] - @timing[:nodsl]) / @timing[:nodsl])
49
+ difference.should be < permitted_dsl_performance_penalty, "DSL generation was more than #{permitted_dsl_performance_penalty}% slower than non-DSL"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+ require 'rubygems'
10
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
11
+ require 'compositor'
12
+
13
+ Dir['spec/support/**/*.rb'].each { |filename| require_relative "../#{filename}" }
14
+
15
+ RSpec.configure do |config|
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+ config.order = 'random'
20
+ end
@@ -0,0 +1,33 @@
1
+ module Compositor
2
+ class Leaf::DslString < Compositor::Leaf
3
+ def to_hash
4
+ {
5
+ a: "b"
6
+ }
7
+ end
8
+ end
9
+
10
+ class Leaf::DslInt < Compositor::Leaf
11
+ attr_accessor :number
12
+
13
+ def initialize(view_context, number, attrs = {})
14
+ super(view_context, {number: number}.merge!(attrs))
15
+ end
16
+
17
+ def to_hash
18
+ with_root_element do
19
+ {
20
+ number: @number
21
+ }
22
+ end
23
+ end
24
+ end
25
+
26
+ class Leaf::DslObject < Compositor::Leaf
27
+ def to_hash
28
+ {
29
+ a: object
30
+ }
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: compositor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Konstantin Gredeskoul
9
+ - Paul Henry
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-05-29 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: guard-rspec
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rb-fsevent
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ description: Composite design pattern with a convenient DSL for building JSON/Hashes
64
+ of complex objects
65
+ email:
66
+ - kigster@gmail.com
67
+ - paul@wanelo.com
68
+ executables: []
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - .gitignore
73
+ - .pairs
74
+ - .rspec
75
+ - .travis.yml
76
+ - Gemfile
77
+ - Guardfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - compositor.gemspec
82
+ - lib/compositor.rb
83
+ - lib/compositor/base.rb
84
+ - lib/compositor/composite.rb
85
+ - lib/compositor/dsl.rb
86
+ - lib/compositor/hash.rb
87
+ - lib/compositor/leaf.rb
88
+ - lib/compositor/list.rb
89
+ - lib/compositor/renderer/base.rb
90
+ - lib/compositor/renderer/iterator.rb
91
+ - lib/compositor/renderer/merged.rb
92
+ - lib/compositor/version.rb
93
+ - spec/compositor/compositor_spec.rb
94
+ - spec/compositor/performance_spec.rb
95
+ - spec/spec_helper.rb
96
+ - spec/support/sample_dsl.rb
97
+ homepage: https://github.com/wanelo/compositor
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Composite design pattern with a convenient DSL for building JSON/Hashes of
121
+ complex objects
122
+ test_files:
123
+ - spec/compositor/compositor_spec.rb
124
+ - spec/compositor/performance_spec.rb
125
+ - spec/spec_helper.rb
126
+ - spec/support/sample_dsl.rb
127
+ has_rdoc: