json_factory 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +43 -52
- data/examples/benchmark.rb +6 -4
- data/examples/fixtures/_test_partial.jfactory +1 -1
- data/examples/fixtures/test.jfactory +8 -6
- data/examples/readme_examples.rb +18 -17
- data/json_factory.gemspec +3 -5
- data/lib/json_factory.rb +24 -11
- data/lib/json_factory/builder.rb +25 -0
- data/lib/json_factory/cache.rb +6 -12
- data/lib/json_factory/configuration.rb +19 -0
- data/lib/json_factory/converter.rb +16 -0
- data/lib/json_factory/dsl.rb +196 -0
- data/lib/json_factory/dsl/object_array.rb +34 -0
- data/lib/json_factory/errors.rb +12 -0
- data/lib/json_factory/json_builder.rb +148 -17
- data/lib/json_factory/railtie.rb +21 -0
- data/lib/json_factory/state.rb +13 -0
- data/lib/json_factory/template_store.rb +31 -0
- data/lib/json_factory/version.rb +1 -1
- metadata +16 -17
- data/lib/json_factory/cache_error.rb +0 -6
- data/lib/json_factory/cache_store_proxy.rb +0 -13
- data/lib/json_factory/cache_store_proxy/base_store_proxy.rb +0 -30
- data/lib/json_factory/cache_store_proxy/file_store_proxy.rb +0 -9
- data/lib/json_factory/cache_store_proxy/memory_store_proxy.rb +0 -9
- data/lib/json_factory/cache_store_proxy/redis_store_proxy.rb +0 -9
- data/lib/json_factory/context.rb +0 -22
- data/lib/json_factory/json_object.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4514793bfcddf9c571232e5cf6bef2f4f0e3604
|
4
|
+
data.tar.gz: e6370cc5a01e97d48237e9ae60b6f23f6acd6d13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c49593eaacc118a094cec4ec95bd5a15c359507f870d2b7911e0445e1c2aeb5f87b065d38cfa67741368f187657dd623ba935bade271d0d7ea455e0ab3e9ce2
|
7
|
+
data.tar.gz: f4ed8f8663d43b36e5f5a4c23af22f6a151470655e4766c27869a12ac1594d62db271aafd67b6853c5760586248485f13e146b7b513b75dc131f9a1431cc7562
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -22,29 +22,33 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
| DSL Method
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
| DSL Method | Description |
|
26
|
+
| ---------- |:------------------------------------------------------------------- |
|
27
|
+
| value | Generates a JSON value. |
|
28
|
+
| object | Generates a JSON object structure. |
|
29
|
+
| member | Adds a key-value pair to a JSON object. |
|
30
|
+
| array | Generates a JSON array structure. |
|
31
|
+
| element | Adds a value to a JSON array. |
|
32
|
+
| partial | Loads the given partial and evaluates it using the local variables. |
|
33
|
+
| cache | Caches the given content under the specified key. |
|
33
34
|
|
34
35
|
##### Top level object JSON structure
|
35
36
|
|
36
37
|
```ruby
|
37
38
|
factory = <<-RUBY
|
38
|
-
json.object
|
39
|
-
json.
|
40
|
-
json.
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
39
|
+
json.object do
|
40
|
+
json.member :data do
|
41
|
+
json.object do
|
42
|
+
json.member :id, object.id
|
43
|
+
json.member :name, object.name
|
44
|
+
json.member :test_array do
|
45
|
+
json.object_array(object.test_objects) do |test_object|
|
46
|
+
json.member :id, test_object.id)
|
47
|
+
json.member :name, test_object.name
|
48
|
+
end
|
49
|
+
end
|
46
50
|
end
|
47
|
-
end
|
51
|
+
end
|
48
52
|
end
|
49
53
|
RUBY
|
50
54
|
|
@@ -53,10 +57,7 @@ test_object_1 = OpenStruct.new(id: '001', name: 'TestObject2')
|
|
53
57
|
test_object_2 = OpenStruct.new(id: '002', name: 'TestObject3')
|
54
58
|
test_object = OpenStruct.new(id: '1', name: 'TestObject1', test_objects: [test_object_1, test_object_2])
|
55
59
|
|
56
|
-
|
57
|
-
context = JSONFactory::Context.new(object: test_object)
|
58
|
-
|
59
|
-
puts JSONFactory::JSONBuilder.new(factory, context).build
|
60
|
+
puts JSONFactory.build(factory, object: test_object)
|
60
61
|
```
|
61
62
|
|
62
63
|
```json
|
@@ -76,9 +77,9 @@ puts JSONFactory::JSONBuilder.new(factory, context).build
|
|
76
77
|
|
77
78
|
```ruby
|
78
79
|
factory = <<-RUBY
|
79
|
-
json.
|
80
|
-
json.member
|
81
|
-
json.member
|
80
|
+
json.object_array objects do |test_object|
|
81
|
+
json.member :id, test_object.id
|
82
|
+
json.member :name, test_object.name
|
82
83
|
end
|
83
84
|
RUBY
|
84
85
|
|
@@ -86,10 +87,7 @@ RUBY
|
|
86
87
|
test_object_1 = OpenStruct.new(id: '001', name: 'TestObject2')
|
87
88
|
test_object_2 = OpenStruct.new(id: '002', name: 'TestObject3')
|
88
89
|
|
89
|
-
|
90
|
-
context = JSONFactory::Context.new(objects: [test_object_1, test_object_2])
|
91
|
-
|
92
|
-
puts JSONFactory::JSONBuilder.new(factory, context).build
|
90
|
+
puts JSONFactory.build(factory, objects: [test_object_1, test_object_2])
|
93
91
|
```
|
94
92
|
|
95
93
|
```json
|
@@ -103,32 +101,29 @@ puts JSONFactory::JSONBuilder.new(factory, context).build
|
|
103
101
|
|
104
102
|
```ruby
|
105
103
|
# tmp/test.jfactory
|
106
|
-
json.member
|
107
|
-
json.member
|
104
|
+
json.member :id, test_object.id
|
105
|
+
json.member :name, test_object.name
|
108
106
|
```
|
109
107
|
|
110
108
|
```ruby
|
111
109
|
# test data
|
112
110
|
test_object = OpenStruct.new(id: '1', name: 'TestObject1')
|
113
111
|
|
114
|
-
#
|
115
|
-
context = JSONFactory::Context.new(object: test_object)
|
116
|
-
|
117
|
-
puts JSONFactory::JSONBuilder.load_factory_file('tmp/test.jfactory', context).build # => { "id": 1, name: "TestObject1" }
|
112
|
+
puts JSONFactory.build('tmp/test.jfactory', object: test_object).build # => { "id": 1, name: "TestObject1" }
|
118
113
|
```
|
119
114
|
|
120
115
|
##### Load partials
|
121
116
|
|
122
117
|
```ruby
|
123
118
|
# tmp/_test_partial.jfactory
|
124
|
-
json.member
|
125
|
-
json.member
|
119
|
+
json.member :id, test_object.id
|
120
|
+
json.member :name, test_object.name
|
126
121
|
```
|
127
122
|
|
128
123
|
```ruby
|
129
124
|
# tmp/test.jfactory
|
130
|
-
json.object
|
131
|
-
json.partial
|
125
|
+
json.object do
|
126
|
+
json.partial 'tmp/test_partial', test_object: object
|
132
127
|
end
|
133
128
|
```
|
134
129
|
|
@@ -136,21 +131,20 @@ end
|
|
136
131
|
# test data
|
137
132
|
test_object = OpenStruct.new(id: '1', name: 'TestObject1')
|
138
133
|
|
139
|
-
#
|
140
|
-
context = JSONFactory::Context.new(object: test_object)
|
141
|
-
|
142
|
-
puts JSONFactory::JSONBuilder.load_factory_file('tmp/test.jfactory', context).build # => { "id": 1, name: "TestObject1" }
|
134
|
+
puts JSONFactory.build('tmp/test.jfactory', object: test_object).build # => { "id": 1, name: "TestObject1" }
|
143
135
|
```
|
144
136
|
|
145
137
|
##### Use cache stores
|
146
138
|
|
147
139
|
```ruby
|
148
140
|
factory = <<-RUBY
|
149
|
-
json.object
|
150
|
-
json.
|
151
|
-
json.
|
152
|
-
json.
|
153
|
-
|
141
|
+
json.object do
|
142
|
+
json.member :data do
|
143
|
+
json.object do
|
144
|
+
json.cache 'test-cache-key' do
|
145
|
+
json.member :id, object.id
|
146
|
+
json.member :name, object.name
|
147
|
+
end
|
154
148
|
end
|
155
149
|
end
|
156
150
|
end
|
@@ -159,12 +153,9 @@ RUBY
|
|
159
153
|
# test data
|
160
154
|
test_object = OpenStruct.new(id: '1', name: 'TestObject1')
|
161
155
|
|
162
|
-
|
163
|
-
context = JSONFactory::Context.new(object: test_object)
|
156
|
+
JSONFactory::Cache.instance.store = ActiveSupport::Cache::MemoryStore.new
|
164
157
|
|
165
|
-
|
166
|
-
builder.cache.store = ActiveSupport::Cache::MemoryStore.new
|
167
|
-
puts builder.build # => { "data": { "id": "1", "name": "TestObject1" } }
|
158
|
+
puts JSONFactory.build(factory, object: test_object) # => { "data": { "id": "1", "name": "TestObject1" } }
|
168
159
|
```
|
169
160
|
|
170
161
|
## Development
|
data/examples/benchmark.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup
|
5
|
+
|
3
6
|
require 'jbuilder'
|
4
7
|
require 'benchmark'
|
5
8
|
require 'forgery'
|
6
9
|
|
7
|
-
|
10
|
+
require 'json_factory'
|
8
11
|
|
9
12
|
objects = []
|
10
13
|
sub_array = []
|
@@ -28,9 +31,8 @@ end
|
|
28
31
|
end
|
29
32
|
|
30
33
|
# CURRENT RUNTIME WITH 1000 and 10 = 0.133410
|
31
|
-
Benchmark.bmbm(
|
34
|
+
Benchmark.bmbm(10) do |x|
|
32
35
|
x.report(:json_factory) do
|
33
|
-
|
34
|
-
builder.build(JSONFactory::Context.new(objects: objects))
|
36
|
+
JSONFactory.build('fixtures/test.jfactory', objects: objects)
|
35
37
|
end
|
36
38
|
end
|
@@ -1 +1 @@
|
|
1
|
-
json.member
|
1
|
+
json.member :id, id
|
@@ -1,8 +1,10 @@
|
|
1
|
-
json.
|
2
|
-
json.member
|
3
|
-
json.member
|
4
|
-
json.member
|
5
|
-
json.
|
6
|
-
json.
|
1
|
+
json.object_array(objects) do |test_object|
|
2
|
+
json.member :id, test_object.id
|
3
|
+
json.member :name, test_object.name
|
4
|
+
json.member :description, test_object.description
|
5
|
+
json.member :test_array do
|
6
|
+
json.object_array(test_object.test_array) do |test_sub_object|
|
7
|
+
json.partial 'fixtures/test_partial', id: test_sub_object.id
|
8
|
+
end
|
7
9
|
end
|
8
10
|
end
|
data/examples/readme_examples.rb
CHANGED
@@ -1,19 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../lib/json_factory'
|
2
4
|
|
3
5
|
# test data
|
4
|
-
|
5
|
-
|
6
|
-
test_object = OpenStruct.new(id: '1', name: 'TestObject1', description: 'Test2', test_objects: [
|
6
|
+
test_object1 = OpenStruct.new(id: '001', name: 'TestObject2')
|
7
|
+
test_object2 = OpenStruct.new(id: '002', name: 'TestObject3')
|
8
|
+
test_object = OpenStruct.new(id: '1', name: 'TestObject1', description: 'Test2', test_objects: [test_object1, test_object2])
|
7
9
|
|
8
10
|
factory = <<-RUBY
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
object! do
|
12
|
+
object!(:data) do
|
13
|
+
member!(:id, object.id)
|
14
|
+
member!(:name, object.name)
|
15
|
+
member!(:test_array) do
|
16
|
+
array!(object.test_objects) do |test_object|
|
17
|
+
member!(:id, test_object.id)
|
18
|
+
member!(:name, test_object.name)
|
19
|
+
end
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
@@ -24,15 +27,13 @@ context = JSONFactory::Context.new(object: test_object)
|
|
24
27
|
|
25
28
|
puts JSONFactory::JSONBuilder.new(factory, context).build
|
26
29
|
|
27
|
-
|
28
|
-
|
29
30
|
factory = <<-RUBY
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
array! objects do |test_object|
|
32
|
+
member!(:id, test_object.id)
|
33
|
+
member!(:name, test_object.name)
|
33
34
|
end
|
34
35
|
RUBY
|
35
36
|
# create context object
|
36
|
-
context = JSONFactory::Context.new(objects: [
|
37
|
+
context = JSONFactory::Context.new(objects: [test_object1, test_object2])
|
37
38
|
|
38
39
|
puts JSONFactory::JSONBuilder.new(factory, context).build
|
data/json_factory.gemspec
CHANGED
@@ -7,11 +7,9 @@ require 'json_factory/version'
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = 'json_factory'
|
9
9
|
spec.version = JSONFactory::VERSION
|
10
|
-
spec.
|
11
|
-
spec.email = ['alex.klaiber@gmail.com']
|
10
|
+
spec.author = 'Alexander Klaiber'
|
12
11
|
|
13
|
-
spec.summary = 'JsonFactory is a
|
14
|
-
spec.description = 'JsonFactory is a Easy DSL to create JSON structures with the development focus on performance.'
|
12
|
+
spec.summary = 'JsonFactory is a easy DSL to create JSON structures with a development focus on performance.'
|
15
13
|
spec.homepage = 'https://github.com/aklaiber/json_factory'
|
16
14
|
spec.license = 'MIT'
|
17
15
|
|
@@ -19,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
19
17
|
spec.require_paths = ['lib']
|
20
18
|
|
21
19
|
spec.add_runtime_dependency 'activesupport', '>= 5.1.0'
|
22
|
-
spec.add_runtime_dependency '
|
20
|
+
spec.add_runtime_dependency 'json'
|
23
21
|
spec.add_runtime_dependency 'redis-activesupport', '>= 5.0.0'
|
24
22
|
|
25
23
|
spec.add_development_dependency 'bundler'
|
data/lib/json_factory.rb
CHANGED
@@ -1,21 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'oj'
|
4
|
-
|
5
3
|
require 'active_support'
|
6
4
|
require 'active_support/cache/redis_store'
|
7
5
|
|
6
|
+
require 'json_factory/railtie' if defined?(Rails)
|
7
|
+
|
8
8
|
require_relative 'json_factory/version'
|
9
|
-
require_relative 'json_factory/
|
9
|
+
require_relative 'json_factory/configuration'
|
10
|
+
require_relative 'json_factory/errors'
|
11
|
+
require_relative 'json_factory/state'
|
12
|
+
require_relative 'json_factory/converter'
|
13
|
+
require_relative 'json_factory/dsl'
|
14
|
+
require_relative 'json_factory/dsl/object_array'
|
15
|
+
require_relative 'json_factory/template_store'
|
10
16
|
require_relative 'json_factory/json_builder'
|
11
|
-
require_relative 'json_factory/
|
17
|
+
require_relative 'json_factory/builder'
|
12
18
|
|
13
19
|
module JSONFactory
|
14
|
-
autoload :Cache,
|
15
|
-
autoload :
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
autoload :Cache, 'json_factory/cache'
|
21
|
+
autoload :TemplateStore, 'json_factory/template_store.rb'
|
22
|
+
|
23
|
+
def self.build(template, local_variables = {})
|
24
|
+
Builder.new(template, local_variables).build
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.configure
|
28
|
+
if block_given?
|
29
|
+
yield Configuration.instance
|
30
|
+
else
|
31
|
+
Configuration.instance
|
32
|
+
end
|
33
|
+
end
|
21
34
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONFactory
|
4
|
+
class Builder
|
5
|
+
def initialize(template, local_variables = {})
|
6
|
+
@io = StringIO.new
|
7
|
+
@template = template
|
8
|
+
@local_variables = local_variables
|
9
|
+
end
|
10
|
+
|
11
|
+
def context
|
12
|
+
@local_variables
|
13
|
+
end
|
14
|
+
|
15
|
+
def build
|
16
|
+
json_builder = JSONBuilder.new(@io)
|
17
|
+
if File.exist?(@template)
|
18
|
+
json_builder.render_template(@template, @local_variables)
|
19
|
+
else
|
20
|
+
json_builder.render_string(@template, @local_variables)
|
21
|
+
end
|
22
|
+
@io.string
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/json_factory/cache.rb
CHANGED
@@ -3,24 +3,18 @@
|
|
3
3
|
module JSONFactory
|
4
4
|
class Cache
|
5
5
|
include Singleton
|
6
|
-
|
7
|
-
attr_accessor :prefix
|
6
|
+
attr_accessor :store, :prefix
|
8
7
|
|
9
8
|
def initialize
|
10
9
|
@prefix = 'json_factory'
|
11
|
-
|
12
|
-
self.store = ::Rails.cache if defined?(::Rails.cache)
|
13
10
|
end
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def store=(store)
|
19
|
-
@store = CacheStoreProxy.build(store)
|
12
|
+
def transform_key(key)
|
13
|
+
[prefix, key].compact.join(':')
|
20
14
|
end
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
def fetch(key, options = nil, &block)
|
17
|
+
store.fetch(transform_key(key), options, &block)
|
18
|
+
end
|
25
19
|
end
|
26
20
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module JSONFactory
|
6
|
+
class Configuration
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
attr_reader :helpers
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@helpers = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def include_helper(mod)
|
16
|
+
@helpers.push(mod)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module JSONFactory
|
6
|
+
module Converter
|
7
|
+
def self.json_key(object)
|
8
|
+
json_value(object.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.json_value(object)
|
12
|
+
raise "don't know how to convert #{object.inspect} (#{object.class})" unless object.respond_to?(:to_json)
|
13
|
+
object.to_json
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONFactory
|
4
|
+
class DSL
|
5
|
+
def self.check_arity(argc, expected)
|
6
|
+
return if expected === argc # rubocop:disable Style/CaseEquality
|
7
|
+
raise ArgumentError, "wrong number of arguments (given #{argc}, expected #{expected})"
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(builder)
|
11
|
+
@builder = builder
|
12
|
+
end
|
13
|
+
|
14
|
+
# :call-seq:
|
15
|
+
# json.value(value) -> nil
|
16
|
+
#
|
17
|
+
# Generates a JSON value.
|
18
|
+
#
|
19
|
+
# json.value 1 # generates: 1
|
20
|
+
# json.value nil # generates: null
|
21
|
+
# json.value :foo # generates: "foo"
|
22
|
+
def value(value)
|
23
|
+
warn 'given block not used' if block_given?
|
24
|
+
@builder.value(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
# :call-seq:
|
28
|
+
# json.array -> nil
|
29
|
+
# json.array { block } -> nil
|
30
|
+
#
|
31
|
+
# Generates a JSON array structure.
|
32
|
+
#
|
33
|
+
# The block is evaluated in order to add element to the array.
|
34
|
+
#
|
35
|
+
# If no block is given, an empty array is generated.
|
36
|
+
#
|
37
|
+
# json.array
|
38
|
+
# # generates: []
|
39
|
+
#
|
40
|
+
# json.array do
|
41
|
+
# json.element 1
|
42
|
+
# json.element 2
|
43
|
+
# end
|
44
|
+
# # generates: [1,2]
|
45
|
+
def array(&block)
|
46
|
+
@builder.array(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# :call-seq:
|
50
|
+
# json.element(value) -> nil
|
51
|
+
# json.element { block } -> nil
|
52
|
+
#
|
53
|
+
# Adds a value to a JSON array. Results in an exception if called outside an
|
54
|
+
# array.
|
55
|
+
#
|
56
|
+
# If an argument is given, it is used as the element's value.
|
57
|
+
#
|
58
|
+
# If a block is given, it is evaluated in order to add nested structures.
|
59
|
+
#
|
60
|
+
# json.array do
|
61
|
+
# json.element 1
|
62
|
+
# json.element 2
|
63
|
+
# json.element do
|
64
|
+
# json.array do
|
65
|
+
# json.element 3
|
66
|
+
# json.element 4
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
# # generates: [1,2,[3,4]]
|
71
|
+
def element(*args)
|
72
|
+
if block_given?
|
73
|
+
DSL.check_arity(args.length, 0..1)
|
74
|
+
warn 'block supersedes value argument' if args.length == 1 && block_given?
|
75
|
+
@builder.element { yield }
|
76
|
+
else
|
77
|
+
DSL.check_arity(args.length, 1)
|
78
|
+
@builder.element(*args)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# :call-seq:
|
83
|
+
# json.object -> nil
|
84
|
+
# json.object { block } -> nil
|
85
|
+
#
|
86
|
+
# Generates a JSON object structure.
|
87
|
+
#
|
88
|
+
# The block is evaluated in order to add key-value pairs to the object.
|
89
|
+
#
|
90
|
+
# If no block is given, an empty object is generated.
|
91
|
+
#
|
92
|
+
# json.object
|
93
|
+
# # generates: {}
|
94
|
+
#
|
95
|
+
# json.object do
|
96
|
+
# json.member :foo, 1
|
97
|
+
# json.member :bar, 2
|
98
|
+
# end
|
99
|
+
# # generates: {"foo":1,"bar":2}
|
100
|
+
def object
|
101
|
+
if block_given?
|
102
|
+
@builder.object { yield }
|
103
|
+
else
|
104
|
+
@builder.object
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# :call-seq:
|
109
|
+
# json.member(key, value) -> nil
|
110
|
+
# json.member(key) { block } -> nil
|
111
|
+
#
|
112
|
+
# Adds a key-value pair to a JSON object. Results in an exception if called
|
113
|
+
# outside an object.
|
114
|
+
#
|
115
|
+
# The first argument is used as the key. If a second argument is given, it
|
116
|
+
# is used as the member's value.
|
117
|
+
#
|
118
|
+
# If a block is given, it is evaluated in order to add nested structures.
|
119
|
+
#
|
120
|
+
# json.object do
|
121
|
+
# json.member :foo, 1
|
122
|
+
# json.member :bar, 2
|
123
|
+
# json.member :baz do
|
124
|
+
# json.array do
|
125
|
+
# json.element 3
|
126
|
+
# json.element 4
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
# # generates: {"foo":1,"bar":2,"baz":[3,4]}
|
131
|
+
def member(*args)
|
132
|
+
if block_given?
|
133
|
+
DSL.check_arity(args.length, 1..2)
|
134
|
+
warn 'block supersedes value argument' if args.length == 2 && block_given?
|
135
|
+
@builder.member(*args) { yield }
|
136
|
+
else
|
137
|
+
DSL.check_arity(args.length, 2)
|
138
|
+
@builder.member(*args)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# :call-seq:
|
143
|
+
# json.cache(key) { block } -> nil
|
144
|
+
#
|
145
|
+
# Caches the given content under the specified key.
|
146
|
+
#
|
147
|
+
# If a cache entry is found, it is added to the output. Otherwise, the given
|
148
|
+
# block is evaluated and the result is stored in the cache.
|
149
|
+
#
|
150
|
+
# json.object do
|
151
|
+
# json.member :foo, 1
|
152
|
+
# cache 'test-key' do
|
153
|
+
# json.member :bar, 2 # will be stored in the cache
|
154
|
+
# end
|
155
|
+
# cache 'test-key' do
|
156
|
+
# json.member :baz, 3 # will be ignored
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
# # generates: {"foo":1,"bar":2,"bar":2}
|
160
|
+
#
|
161
|
+
# When caching object members or array elements, commas are inserted as
|
162
|
+
# needed. However, no further checks are performed, so improper use may
|
163
|
+
# result in invalid JSON, for example by adding cached object members to an
|
164
|
+
# array.
|
165
|
+
def cache(key)
|
166
|
+
@builder.cache(key) { yield }
|
167
|
+
end
|
168
|
+
|
169
|
+
# :call-seq:
|
170
|
+
# json.partial(file, local_variables = {})
|
171
|
+
#
|
172
|
+
# Loads the given partial and evaluates it using the local variables.
|
173
|
+
#
|
174
|
+
# # simple.jfactory
|
175
|
+
# json.object do
|
176
|
+
# json.member :name, name
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# json.array do
|
180
|
+
# json.element do
|
181
|
+
# json.partial 'simple.jfactory', name: 'foo'
|
182
|
+
# end
|
183
|
+
# json.element do
|
184
|
+
# json.partial 'simple.jfactory', name: 'bar'
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
# # generates: [{"name":"foo"},{"name":"bar"}]
|
188
|
+
#
|
189
|
+
# Partial files are loaded only once to minimize file access.
|
190
|
+
def partial(file, local_variables = {})
|
191
|
+
path = Pathname.new(File.expand_path(file))
|
192
|
+
path = "#{path.dirname}/_#{path.basename}.jfactory" if path.extname.empty?
|
193
|
+
@builder.partial(path.to_s, local_variables)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONFactory
|
4
|
+
class DSL
|
5
|
+
# Helper method to generate an array of objects.
|
6
|
+
#
|
7
|
+
# json.object_array([1,2,3]) do |id|
|
8
|
+
# json.member :id, id
|
9
|
+
# end
|
10
|
+
# # generates: [{"id":1},{"id":2},{"id":2}]
|
11
|
+
#
|
12
|
+
# The above is equivalent to:
|
13
|
+
#
|
14
|
+
# json.array do
|
15
|
+
# [1,2,3].each do |id|
|
16
|
+
# json.object do
|
17
|
+
# json.member :id, id
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# # generates: [{"id":1},{"id":2},{"id":2}]
|
22
|
+
def object_array(collection)
|
23
|
+
array do
|
24
|
+
collection.each do |*values|
|
25
|
+
element do
|
26
|
+
object do
|
27
|
+
yield(*values)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -2,30 +2,161 @@
|
|
2
2
|
|
3
3
|
module JSONFactory
|
4
4
|
class JSONBuilder
|
5
|
-
|
6
|
-
attr_reader :stream, :factory, :cache
|
5
|
+
BUILDER_VARIABLE_NAME = :json
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
TOKEN_LEFT_SQUARE_BRACKET = '['
|
8
|
+
TOKEN_RIGHT_SQUARE_BRACKET = ']'
|
9
|
+
TOKEN_LEFT_CURLY_BRACKET = '{'
|
10
|
+
TOKEN_RIGHT_CURLY_BRACKET = '}'
|
11
|
+
TOKEN_COLON = ':'
|
12
|
+
TOKEN_COMMA = ','
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@
|
14
|
+
def initialize(io, type = :value)
|
15
|
+
@stack = [State.new(io, type)]
|
16
16
|
@cache = Cache.instance
|
17
|
-
@
|
17
|
+
@template_store = TemplateStore.instance
|
18
|
+
end
|
19
|
+
|
20
|
+
def value(value = nil)
|
21
|
+
raise TypeNotAllowedError, 'Can only add value as a value' unless type == :value
|
22
|
+
raise TypeNotAllowedError, 'Cannot add multiple values' unless count.zero?
|
23
|
+
add_value(value)
|
24
|
+
increment_count
|
25
|
+
end
|
26
|
+
|
27
|
+
def array
|
28
|
+
raise TypeNotAllowedError, 'Can only add array as a value' unless type == :value
|
29
|
+
raise TypeNotAllowedError, 'Cannot add multiple values' unless count.zero?
|
30
|
+
|
31
|
+
io << TOKEN_LEFT_SQUARE_BRACKET
|
32
|
+
push_type(:array) { yield } if block_given?
|
33
|
+
io << TOKEN_RIGHT_SQUARE_BRACKET
|
34
|
+
increment_count
|
35
|
+
end
|
36
|
+
|
37
|
+
def element(value = nil)
|
38
|
+
raise TypeNotAllowedError, 'Can only add an element within an array' unless type == :array
|
39
|
+
|
40
|
+
add_separator
|
41
|
+
if block_given?
|
42
|
+
push_type(:value) { yield }
|
43
|
+
else
|
44
|
+
add_value(value)
|
45
|
+
end
|
46
|
+
increment_count
|
47
|
+
end
|
48
|
+
|
49
|
+
def object
|
50
|
+
raise TypeNotAllowedError, 'Can only add object as a value' unless type == :value
|
51
|
+
raise TypeNotAllowedError, 'Cannot add multiple values' unless count.zero?
|
52
|
+
|
53
|
+
io << TOKEN_LEFT_CURLY_BRACKET
|
54
|
+
push_type(:object) { yield } if block_given?
|
55
|
+
io << TOKEN_RIGHT_CURLY_BRACKET
|
56
|
+
increment_count
|
57
|
+
end
|
58
|
+
|
59
|
+
def member(key, value = nil)
|
60
|
+
raise TypeNotAllowedError, 'Can only add a member within an object' unless type == :object
|
61
|
+
|
62
|
+
add_separator
|
63
|
+
io << Converter.json_key(key)
|
64
|
+
io << TOKEN_COLON
|
65
|
+
if block_given?
|
66
|
+
push_type(:value) { yield }
|
67
|
+
else
|
68
|
+
add_value(value)
|
69
|
+
end
|
70
|
+
increment_count
|
71
|
+
end
|
72
|
+
|
73
|
+
def cache(key)
|
74
|
+
value = @cache.fetch(key) do
|
75
|
+
cache_io = StringIO.new
|
76
|
+
push_io(cache_io) { yield }
|
77
|
+
cache_io.string
|
78
|
+
end
|
79
|
+
raise EmptyValueError if value.empty?
|
80
|
+
|
81
|
+
add_separator
|
82
|
+
io << value
|
83
|
+
increment_count
|
84
|
+
end
|
85
|
+
|
86
|
+
def evaluate(string, local_variables, filename)
|
87
|
+
binding = jfactory
|
88
|
+
local_variables.each_pair do |key, value|
|
89
|
+
binding.local_variable_set(key, value)
|
90
|
+
end
|
91
|
+
binding.local_variable_set(BUILDER_VARIABLE_NAME, DSL.new(self))
|
92
|
+
eval(string, binding, filename.to_s) # rubocop:disable Security/Eval
|
93
|
+
end
|
94
|
+
|
95
|
+
def render_template(filename, local_variables)
|
96
|
+
template = @template_store.get(filename)
|
97
|
+
evaluate(template, local_variables, filename)
|
98
|
+
end
|
99
|
+
alias partial render_template
|
100
|
+
|
101
|
+
def render_string(string, local_variables)
|
102
|
+
evaluate(string, local_variables, '(inline)')
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def add_value(value)
|
108
|
+
io << Converter.json_value(value)
|
18
109
|
end
|
19
110
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
111
|
+
def add_separator
|
112
|
+
io << TOKEN_COMMA unless count.zero?
|
113
|
+
end
|
114
|
+
|
115
|
+
def io
|
116
|
+
@stack.last.io
|
117
|
+
end
|
118
|
+
|
119
|
+
def type
|
120
|
+
@stack.last.type
|
121
|
+
end
|
122
|
+
|
123
|
+
def count
|
124
|
+
@stack.last.count
|
125
|
+
end
|
126
|
+
|
127
|
+
def increment_count
|
128
|
+
@stack.last.count += 1
|
129
|
+
end
|
130
|
+
|
131
|
+
def push_io(io)
|
132
|
+
@stack.push(State.new(io, type))
|
133
|
+
yield
|
134
|
+
@stack.pop
|
135
|
+
end
|
136
|
+
|
137
|
+
def push_type(type)
|
138
|
+
@stack.push(State.new(io, type))
|
139
|
+
yield
|
140
|
+
raise EmptyValueError if type == :value && count.zero?
|
141
|
+
@stack.pop
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
23
145
|
|
24
|
-
|
25
|
-
|
26
|
-
|
146
|
+
JSONFactory::JSONBuilder.class_eval do
|
147
|
+
# Returns an empty evaluation context, similar to Ruby's main object.
|
148
|
+
def jfactory
|
149
|
+
Object.allocate.instance_eval do
|
150
|
+
class << self
|
151
|
+
JSONFactory.configure.helpers.each { |mod| include mod }
|
27
152
|
|
28
|
-
|
153
|
+
def to_s
|
154
|
+
'jfactory'
|
155
|
+
end
|
156
|
+
alias inspect to_s
|
157
|
+
end
|
158
|
+
return binding
|
29
159
|
end
|
30
160
|
end
|
161
|
+
private :jfactory
|
31
162
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONFactory
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
initializer 'json_factory.cache' do
|
6
|
+
Cache.instance.store = Rails.cache
|
7
|
+
end
|
8
|
+
|
9
|
+
initializer 'json_factory.jfactory_watcher' do |app|
|
10
|
+
jfactory_reloader = app.config.file_watcher.new(Dir.glob(::Rails.root.join('app/views/**/*.jfactory'))) do
|
11
|
+
TemplateStore.instance.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
app.reloaders << jfactory_reloader
|
15
|
+
|
16
|
+
config.to_prepare do
|
17
|
+
jfactory_reloader.execute_if_updated
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONFactory
|
4
|
+
class TemplateStore
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@templates = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(path)
|
12
|
+
if @templates.key? path
|
13
|
+
@templates.fetch(path)
|
14
|
+
else
|
15
|
+
@templates.store(path, read_template(path))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear
|
20
|
+
@templates.clear
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def read_template(path)
|
26
|
+
raise "file format is invalid. #{path}" unless File.extname(path).eql?('.jfactory')
|
27
|
+
raise "jfactory file #{path} not found" unless File.exist?(path)
|
28
|
+
File.read(path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/json_factory/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_factory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Klaiber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 5.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -150,10 +150,8 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
description:
|
154
|
-
|
155
|
-
email:
|
156
|
-
- alex.klaiber@gmail.com
|
153
|
+
description:
|
154
|
+
email:
|
157
155
|
executables: []
|
158
156
|
extensions: []
|
159
157
|
extra_rdoc_files: []
|
@@ -176,16 +174,17 @@ files:
|
|
176
174
|
- examples/readme_examples.rb
|
177
175
|
- json_factory.gemspec
|
178
176
|
- lib/json_factory.rb
|
177
|
+
- lib/json_factory/builder.rb
|
179
178
|
- lib/json_factory/cache.rb
|
180
|
-
- lib/json_factory/
|
181
|
-
- lib/json_factory/
|
182
|
-
- lib/json_factory/
|
183
|
-
- lib/json_factory/
|
184
|
-
- lib/json_factory/
|
185
|
-
- lib/json_factory/cache_store_proxy/redis_store_proxy.rb
|
186
|
-
- lib/json_factory/context.rb
|
179
|
+
- lib/json_factory/configuration.rb
|
180
|
+
- lib/json_factory/converter.rb
|
181
|
+
- lib/json_factory/dsl.rb
|
182
|
+
- lib/json_factory/dsl/object_array.rb
|
183
|
+
- lib/json_factory/errors.rb
|
187
184
|
- lib/json_factory/json_builder.rb
|
188
|
-
- lib/json_factory/
|
185
|
+
- lib/json_factory/railtie.rb
|
186
|
+
- lib/json_factory/state.rb
|
187
|
+
- lib/json_factory/template_store.rb
|
189
188
|
- lib/json_factory/version.rb
|
190
189
|
homepage: https://github.com/aklaiber/json_factory
|
191
190
|
licenses:
|
@@ -210,6 +209,6 @@ rubyforge_project:
|
|
210
209
|
rubygems_version: 2.6.11
|
211
210
|
signing_key:
|
212
211
|
specification_version: 4
|
213
|
-
summary: JsonFactory is a
|
214
|
-
|
212
|
+
summary: JsonFactory is a easy DSL to create JSON structures with a development focus
|
213
|
+
on performance.
|
215
214
|
test_files: []
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module JSONFactory
|
4
|
-
module CacheStoreProxy
|
5
|
-
PROXIES = [RedisStoreProxy, MemoryStoreProxy, FileStoreProxy].freeze
|
6
|
-
|
7
|
-
def self.build(store)
|
8
|
-
store_proxy = PROXIES.find { |proxy| proxy.handle?(store) }
|
9
|
-
fail CacheError, "#{store.class} is a not supported cache" if store_proxy.nil?
|
10
|
-
store_proxy.new(store)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module JSONFactory
|
4
|
-
module CacheStoreProxy
|
5
|
-
class BaseStoreProxy
|
6
|
-
attr_reader :store
|
7
|
-
|
8
|
-
def self.handle?(store)
|
9
|
-
defined?(self::STORE_CLASS) && store.is_a?(self::STORE_CLASS)
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(store, prefix = 'json_factory')
|
13
|
-
@store = store
|
14
|
-
@prefix = prefix
|
15
|
-
end
|
16
|
-
|
17
|
-
def read(key, options = nil)
|
18
|
-
store.read("#{@prefix}:#{key}", options)
|
19
|
-
end
|
20
|
-
|
21
|
-
def write(key, value, options = nil)
|
22
|
-
store.write("#{@prefix}:#{key}", value, options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def delete(key, options = nil)
|
26
|
-
store.delete("#{@prefix}:#{key}", options)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/json_factory/context.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module JSONFactory
|
4
|
-
class Context
|
5
|
-
def initialize(data = nil)
|
6
|
-
@data = data
|
7
|
-
end
|
8
|
-
|
9
|
-
def add(key, value)
|
10
|
-
@data[key] = value
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing(method_name, *arguments, &block)
|
14
|
-
return @data[method_name] if @data.is_a?(Hash) && @data.key?(method_name)
|
15
|
-
super
|
16
|
-
end
|
17
|
-
|
18
|
-
def respond_to_missing?(method_name, include_private = false)
|
19
|
-
(@data.is_a?(Hash) && @data.key?(method_name)) || super
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
module JSONFactory
|
2
|
-
class JSONObject
|
3
|
-
attr_reader :json_builder
|
4
|
-
attr_accessor :context
|
5
|
-
|
6
|
-
@@partials = {}
|
7
|
-
|
8
|
-
def initialize(json_builder, context = nil)
|
9
|
-
@json_builder = json_builder
|
10
|
-
@context = context
|
11
|
-
end
|
12
|
-
|
13
|
-
def open_object
|
14
|
-
json_builder.stream.push_object
|
15
|
-
end
|
16
|
-
|
17
|
-
def close_object
|
18
|
-
json_builder.stream.pop
|
19
|
-
end
|
20
|
-
|
21
|
-
def schema!(object = nil)
|
22
|
-
yield self, object
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def object!(key = nil, &block)
|
27
|
-
json_object = JSONObject.new(json_builder)
|
28
|
-
|
29
|
-
json_builder.stream.push_key(key.to_s) if key
|
30
|
-
|
31
|
-
json_object.open_object
|
32
|
-
json_object.schema!(&block)
|
33
|
-
json_object.close_object
|
34
|
-
end
|
35
|
-
|
36
|
-
def array!(array, key = nil, &block)
|
37
|
-
json_builder.stream.push_array(key ? key.to_s : nil)
|
38
|
-
array.each do |object|
|
39
|
-
builder = JSONObject.new(json_builder)
|
40
|
-
builder.open_object
|
41
|
-
builder.schema!(object, &block)
|
42
|
-
builder.close_object
|
43
|
-
end
|
44
|
-
json_builder.stream.pop
|
45
|
-
end
|
46
|
-
|
47
|
-
def member!(key, value = nil)
|
48
|
-
json_builder.stream.push_value(value, key.to_s)
|
49
|
-
end
|
50
|
-
|
51
|
-
def null!
|
52
|
-
json_builder.output.seek(json_builder.output.pos - 1)
|
53
|
-
json_builder.output.puts('null')
|
54
|
-
end
|
55
|
-
|
56
|
-
def cache!(cache_key, &block)
|
57
|
-
json = json_builder.cache.read(cache_key) if cache_key && json_builder.cache
|
58
|
-
return json_builder.output.puts(json) unless json.blank?
|
59
|
-
|
60
|
-
start_cache_pos = json_builder.output.pos
|
61
|
-
self.schema!(&block)
|
62
|
-
end_cache_pos = json_builder.output.pos
|
63
|
-
|
64
|
-
json_builder.cache.write(cache_key, json_builder.output.string[start_cache_pos..end_cache_pos])
|
65
|
-
end
|
66
|
-
|
67
|
-
def partial!(path, data = {})
|
68
|
-
path = Pathname.new(path)
|
69
|
-
|
70
|
-
if path.extname.eql?('.jfactory')
|
71
|
-
@@partials[path] ||= File.open(path).read
|
72
|
-
else
|
73
|
-
@@partials[path] ||= File.open("#{path.dirname}/_#{path.basename}.jfactory").read
|
74
|
-
end
|
75
|
-
|
76
|
-
JSONObject.new(json_builder, JSONFactory::Context.new(data)).schema! do |json|
|
77
|
-
json.instance_eval(@@partials[path])
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def method_missing(method_name, *arguments, &block)
|
82
|
-
return context.send(method_name) if context.respond_to?(method_name)
|
83
|
-
super
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|