Skip to content

Commit

Permalink
feat: add support for symbolic name reference in extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
adamluzsi committed Mar 28, 2016
1 parent 716918c commit 3347f38
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 64 deletions.
15 changes: 15 additions & 0 deletions lib/rack/app/extension.rb
@@ -1,6 +1,21 @@
class Rack::App::Extension

require 'rack/app/extension/factory'

class << self

def names
@names ||= []
end

def name(extension_name_alias)
names << extension_name_alias.to_s.to_sym
end

def inherited(klass)
klass.name(Rack::App::Utils.snake_case(klass.to_s.split('::').last).to_sym)
end

def includes
@includes ||= []
end
Expand Down
13 changes: 13 additions & 0 deletions lib/rack/app/extension/factory.rb
@@ -0,0 +1,13 @@
module Rack::App::Extension::Factory

extend self

def all
ObjectSpace.each_object(Class).select { |klass| klass < ::Rack::App::Extension }
end

def find_for(sym_name)
return all.find{|extension_class| extension_class.names.include?(sym_name) }
end

end
10 changes: 9 additions & 1 deletion lib/rack/app/singleton_methods/settings.rb
Expand Up @@ -20,13 +20,21 @@ def headers(new_headers=nil)

def extensions(*extensions)
extensions.each do |ext|
if ext.is_a?(::Class) && ext < (::Rack::App::Extension)

if ext.is_a?(Symbol)
ext = Rack::App::Extension::Factory::find_for(ext)
end

if ext.is_a?(::Class) && ext < ::Rack::App::Extension

ext.includes.each { |m| include(m) }
ext.extends.each { |m| extend(m) }
ext.inheritances.each { |block| on_inheritance(&block) }

else
raise("unsupported extension reference: #{ext.inspect}")
end

end
end

Expand Down
3 changes: 1 addition & 2 deletions lib/rack/app/test.rb
Expand Up @@ -28,8 +28,7 @@ def rack_app(&block)
app_class = defined?(__rack_app_class__) ? __rack_app_class__ : nil
constructors = []
constructors << __rack_app_constructor__ if defined?(__rack_app_constructor__) and __rack_app_constructor__.is_a?(Proc)
constructors << block unless block.nil?
Rack::App::Test::Utils.rack_app_by(app_class, constructors)
Rack::App::Test::Utils.rack_app_by(app_class, constructors, &block)
end

end
16 changes: 6 additions & 10 deletions lib/rack/app/test/utils.rb
Expand Up @@ -10,17 +10,13 @@ def format_properties(properties)
properties
end

def rack_app_by(rack_app_class, constructors)
subject_app = nil

if constructors.empty?
subject_app = rack_app_class
else
subject_app = Class.new(rack_app_class || ::Rack::App)
constructors.each { |constructor| subject_app.class_eval(&constructor) }
end
def rack_app_by(subject_class, constructors, &block)

app_class = subject_class.respond_to?(:call) ? subject_class : Rack::App
app = Rack::App::Utils.deep_dup(app_class)
constructors.each { |constructor| app.class_eval(&constructor) }

subject_app
block.is_a?(Proc) ? app.instance_exec(&block) : app
end

def env_by(properties)
Expand Down
8 changes: 5 additions & 3 deletions lib/rack/app/utils.rb
Expand Up @@ -20,9 +20,7 @@ def normalize_path(path)
path
end

# Based on ActiveSupport, removed inflections.
# https://github.com/rails/rails/blob/v4.1.0.rc1/activesupport/lib/active_support/inflector/methods.rb
def underscore(camel_cased_word)
def snake_case(camel_cased_word)
word = camel_cased_word.to_s.gsub('::', '/')
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
Expand All @@ -31,6 +29,10 @@ def underscore(camel_cased_word)
word
end

def camel_case(snake_case)
snake_case.to_s.split('_').collect(&:capitalize).join
end

def pwd(*path_parts)

root_folder = if ENV['BUNDLE_GEMFILE']
Expand Down
11 changes: 4 additions & 7 deletions rack-app.gemspec
@@ -1,8 +1,4 @@
# coding: utf-8
# lib = File.expand_path('../lib', __FILE__)
# $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
# require 'rack/app/version'

Gem::Specification.new do |spec|

spec.name = "rack-app"
Expand All @@ -16,10 +12,11 @@ Gem::Specification.new do |spec|
spec.homepage = 'http://www.rack-app.com/'

spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.bindir = "bin"
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }

spec.license = 'Apache License 2.0'

spec.add_development_dependency "bundler"
Expand All @@ -28,4 +25,4 @@ Gem::Specification.new do |spec|

spec.add_dependency "rack"

end
end
65 changes: 24 additions & 41 deletions spec/rack/app/extension_spec.rb
@@ -1,60 +1,43 @@
require 'spec_helper'
require_relative 'extension_spec/example-rack_app_extension'
describe Rack::App::Extension do

class ExampleRackAppExtension < Rack::App::Extension

module ClassMethods

def hello
'hello world'
end

end

module EndpointMethods

def sup
'all good thanks!'
end
require 'rack/app/test'
include Rack::App::Test

end
{
'when class explicitly used' => Example::RackAppExtension,
'when used with default generated symbol' => :rack_app_extension
}.each do |context_message,extension_value|
context context_message do

include EndpointMethods
rack_app do

extend ClassMethods
extensions extension_value

on_inheritance do |parent, child|
child.instance_variable_set(:@dog, 'bark')
end
get '/' do
sup
end

end
end

class SampleAppForExtensionTest < Rack::App
it { expect(get('/').body).to eq 'all good thanks!' }

extensions ExampleRackAppExtension
it { expect(Class.new(rack_app).hello).to eq 'world'}

get '/' do
sup
end
end

end
context 'when unsupported extension reference given' do

it 'should raise an error' do
unsupported_extension_reference = Object.new

describe Rack::App::Extension do
let(:instance) { described_class }

require 'rack/app/test'
include Rack::App::Test

rack_app SampleAppForExtensionTest do

get '/' do
sup
expect{
rack_app{ extensions unsupported_extension_reference }
}.to raise_error("unsupported extension reference: #{unsupported_extension_reference.inspect}")
end

end

it { expect(get('/').body).to eq 'all good thanks!' }

it { expect(rack_app.instance_variable_get(:@dog)).to eq 'bark' }

end
33 changes: 33 additions & 0 deletions spec/rack/app/extension_spec/example-rack_app_extension.rb
@@ -0,0 +1,33 @@
module Example
class RackAppExtension < Rack::App::Extension

module ClassMethods

def hello
'hello world'
end

end

module EndpointMethods

def sup
'all good thanks!'
end

end

include EndpointMethods

extend ClassMethods

on_inheritance do |parent, child|

def child.hello
'world'
end

end

end
end

0 comments on commit 3347f38

Please sign in to comment.