grape-gen 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28745d08b232ed5faeb876a406a2b3f587be9036
4
- data.tar.gz: 44c2dbad904233a90c7b58010d5629004e4c06a4
3
+ metadata.gz: 0e50733ed46b5a0d995856b26debf1b46f85f68f
4
+ data.tar.gz: 667b90bcfc49d876a21bc81c52b4314f4108b627
5
5
  SHA512:
6
- metadata.gz: 1c98b81b1848d883d932044fd6890675e8d12c8630a61003307e9ffb8f789c66e00618a3b97d68a622a9c6e3d746e009d0f080109b32ac320b192ac5f003f88d
7
- data.tar.gz: a96d538140c5d49aac1a0d27e51d5cfd2950757ef39e08e7fcd048643af2f4cd8a3c60e042100696d266a22df8690da7b16ffa521f0e83838f2cb31a6b3e81ba
6
+ metadata.gz: f3d87fc13fe0d3781c44143d1efb4fb95975182d5bcd2dc9e1cfb6a96cb2fe45bae7f545e9d1a8a314df6f2f76864370d6248d8f81af685f457298332e5fc5ff
7
+ data.tar.gz: ce52755d2c38f7303cec926b352464d2e3fdaa94d2776538e3d0503cdd412e6395ee1a394d2a1528926dd946f4af72022a88683963d1769c7637240414ddc910
data/README.md CHANGED
@@ -1,30 +1,76 @@
1
- # Grape::Scaffold
1
+ # Grape::Generate
2
+ Grape application template generator with batteries included
2
3
 
3
- TODO: Write a gem description
4
+ ## Getting started
4
5
 
5
- ## Installation
6
+ First, install gem into your system
6
7
 
7
- Add this line to your application's Gemfile:
8
+ $ gem install 'grape-gen'
9
+ then grape-gen binary will be available in your shell.
10
+ To generate default app skeleton, simply use:
8
11
 
9
- ```ruby
10
- gem 'grape-scaffold'
11
- ```
12
+ $ grape-gen app your_app_name
13
+ After executing complete, dir __your_app_name__ will be created in current dir.
14
+ Navigate into created dir and do ```$ bundle```
12
15
 
13
- And then execute:
16
+ ## Whats included?
17
+ * carrierwave
18
+ * sidekiq
19
+ * faye
20
+ * elastic search
21
+ * redis
14
22
 
15
- $ bundle
23
+ ## Grape API rack app
24
+ Rack app intended to be run under EventMachine-powered server (skeleton app using Thin)
25
+ Every library used is patched to play ball with EventMachine event loop.
26
+ To start web server:
16
27
 
17
- Or install it yourself as:
28
+ $ RACK_ENV=production thin start -p 9292
29
+ Example webserver responding to following API methods:
18
30
 
19
- $ gem install grape-scaffold
31
+ * POST /api/auth/register (display_name, email)
32
+ * POST /api/auth/approve_email (email, email_approvement_code)
33
+ * GET /api/profile
34
+ * PUT /api/profile (avatar, remove_avatar, display_name)
20
35
 
21
- ## Usage
36
+ /api/profile methods is restricted to use only by registered users.
37
+ API user must supply X-Authorize header, received from /api/auth/approve_email
22
38
 
23
- TODO: Write usage instructions here
39
+ When user approves email by calling POST /api/auth/approve_email with valid data,
40
+ message containing user __display_name__ will be published into faye __/user/registered__ channel
41
+ so all faye connections subscribed to /user/registered channel will receive info about newly registered user
42
+
43
+ ## Faye (optional, enabled by default)
44
+ Include faye support into skeleton app.
45
+ To start faye server:
46
+
47
+ $ thin start -p 9393 -R faye.ru -e production
48
+ While running web server and faye server, please, visit http://localhost:9292/faye
49
+ Webpage contains simple implementation of faye client, connecting to localhost:9393 server
50
+ After successful connection client subscribes on two channels: __/user/registered__ and __/time__
51
+ Faye events received displayed at the top of webpage
52
+
53
+ ## Sidekiq (optional, enabled by default)
54
+ Include support for background jobs via Sidekiq gem
55
+ Besides of main Sidekiq gem it also adds gem supporting jobs scheduling
56
+ Out of the box skeleton app have one scheduled job defined - __/jobs/pong_time.rb__
57
+ Job, scheduled to run each 5 seconds, simply publishes current time into /time faye channel
58
+ so all faye connections subscribed to /time channel will receive current time string
59
+ For more information take a look at /config/sidekiq.yml
60
+
61
+ ## Mandrill (optional, enabled by default)
62
+ Include support for email delivery with Mandrill service via MandrillMailer gem.
63
+ To have this gem running you should add your Mandrill api key to __/config/application.yml__
64
+ After successful registration with __POST /api/auth/register__ app tries to send message to user email using __/mailers/registraion_mailer.rb__
65
+ To have email delivered please make sure you have changed __from__ address in __/mailers/registraion_mailer.rb__ and appropriate domain name is registered for api key you add to config.file.
66
+
67
+ ## TODO
68
+
69
+ More documentation
24
70
 
25
71
  ## Contributing
26
72
 
27
- 1. Fork it ( https://github.com/[my-github-username]/grape-scaffold/fork )
73
+ 1. Fork it ( https://github.com/AlexYankee/grape-gen/fork )
28
74
  2. Create your feature branch (`git checkout -b my-new-feature`)
29
75
  3. Commit your changes (`git commit -am 'Add some feature'`)
30
76
  4. Push to the branch (`git push origin my-new-feature`)
@@ -1,5 +1,5 @@
1
1
  module Grape
2
2
  module Generate
3
- VERSION = '0.0.5'
3
+ VERSION = '0.0.6'
4
4
  end
5
5
  end
@@ -43,9 +43,6 @@ module Grape
43
43
 
44
44
  directory './', exclude_pattern: /(sidekiq|carrierwave|faye|mandrill|tire|elastic_search|search_indexes|mailers|uploaders|jobs)/
45
45
 
46
- directory './log'
47
- directory './tmp/pids'
48
-
49
46
  @redis ||= @sidekiq || @faye
50
47
 
51
48
  if @faye
@@ -54,8 +51,7 @@ module Grape
54
51
  copy_file './config/initializers/faye.rb'
55
52
  copy_file './config/initializers/em-patches/faye.rb'
56
53
  copy_file './public/faye.html'
57
- copy_file './lib/faye_auth_extension.rb'
58
- copy_file './lib/faye_publisher.rb'
54
+ directory './lib/faye'
59
55
  end
60
56
 
61
57
  if @sidekiq
data/template/Gemfile.tt CHANGED
@@ -52,6 +52,7 @@ group :utils do
52
52
  gem 'activesupport', '~> 4.2'
53
53
  gem 'multi_json', '~> 1.10.1'
54
54
  gem 'oj', '~> 2.11.2'
55
+ gem 'redis-namespace', '~> 1.5.1'
55
56
  end
56
57
  <%- if @es -%>
57
58
  # ElasticSearch
@@ -34,7 +34,7 @@ module API
34
34
  @user.save
35
35
  header['X-Authorize'] = @user.token
36
36
  <% if @faye %>
37
- FayePublisher.publish('/user/registered', {display_name: @user.display_name})
37
+ Faye::Publisher.instance.publish('/user/registered', {display_name: @user.display_name})
38
38
  <% end %>
39
39
  end
40
40
  end
@@ -18,5 +18,5 @@ ApplicationSettings.source File.expand_path('config/application.yml', APP_ROOT)
18
18
  ApplicationSettings.root = APP_ROOT
19
19
 
20
20
  require_relative 'initializers/logging'
21
- require_relative '../lib/faye_auth_extension'
22
- require_relative '../lib/faye_publisher'
21
+ require_relative '../lib/faye/auth_extension'
22
+ require_relative '../lib/faye/publisher'
@@ -1,4 +1,6 @@
1
1
  require_relative 'redis_lazy_evaluated_pool'
2
- require_relative '../../../lib/faye_publisher'
2
+ require_relative '../../../lib/faye/publisher'
3
3
 
4
- FayePublisher.redis = RedisLazyEvaluatedPool.pool_with_config(ApplicationSettings.faye.redis.to_hash.deep_symbolize_keys)
4
+ Faye::Publisher.configure do |config|
5
+ config.redis = RedisLazyEvaluatedPool.pool_with_config(ApplicationSettings.faye.redis.to_hash.deep_symbolize_keys)
6
+ end
@@ -14,7 +14,7 @@ class LazyEvaluatedPool < EventMachine::Synchrony::ConnectionPool
14
14
  private
15
15
  def acquire(fiber)
16
16
  if conn = @available.pop
17
- conn = self.instance_eval(&conn) if conn.respond_to?(:call)
17
+ conn = conn.call(@config) if conn.respond_to?(:call)
18
18
  @reserved[fiber.object_id] = conn
19
19
  conn
20
20
  else
@@ -26,7 +26,7 @@ class LazyEvaluatedPool < EventMachine::Synchrony::ConnectionPool
26
26
  class << self
27
27
  def pool_with_config(config, &block)
28
28
  config[:size] ||= 10
29
- LazyEvaluatedPool.new(config, &(block || connection))
29
+ new(config, &(block || connection))
30
30
  end
31
31
  private
32
32
  def connection; raise 'Please, override connection method or supply block' end
@@ -1,3 +1,5 @@
1
+ require 'mandrill'
2
+
1
3
  # Patch mandrill API to play ball with EventMachine
2
4
  module Mandrill
3
5
  class API
@@ -1,4 +1,3 @@
1
- require 'redis-namespace'
2
1
  require_relative 'redis'
3
2
  require_relative 'lazy_evaluated_pool'
4
3
 
@@ -9,8 +8,8 @@ class RedisLazyEvaluatedPool < LazyEvaluatedPool
9
8
  }
10
9
  private
11
10
  def self.connection
12
- Proc.new {
13
- config = RedisLazyEvaluatedPool::CONFIG_DEFAULTS.merge (@config|| {}).deep_symbolize_keys
11
+ Proc.new { |config|
12
+ config = RedisLazyEvaluatedPool::CONFIG_DEFAULTS.merge (config|| {}).deep_symbolize_keys
14
13
  connection = EventMachine::Hiredis.connect(config[:url])
15
14
  connection = Redis::Namespace.new(config[:namespace], redis: connection) if config[:namespace]
16
15
  connection
@@ -1,3 +1,5 @@
1
- require_relative '../../lib/faye_publisher'
1
+ require_relative '../../lib/faye/publisher'
2
2
 
3
- FayePublisher.redis = ApplicationSettings.faye.redis unless FayePublisher.configured?
3
+ Faye::Publisher.configure do |config|
4
+ config.redis = ApplicationSettings.faye.redis unless Faye::Publisher.configured?
5
+ end
@@ -1 +1,67 @@
1
- MandrillMailer.config.api = ApplicationSettings.mandrill.api_key
1
+ require 'mandrill'
2
+
3
+ module Mandrill
4
+ constants.select{|c| /Error$/ =~ c.to_s}.each{|const| remove_const(const) }
5
+ class Error < StandardError
6
+ end
7
+ class ValidationError < Error
8
+ end
9
+ class InvalidKeyError < Error
10
+ end
11
+ class PaymentRequiredError < Error
12
+ end
13
+ class UnknownSubaccountError < Error
14
+ end
15
+ class UnknownTemplateError < Error
16
+ end
17
+ class ServiceUnavailableError < Error
18
+ end
19
+ class UnknownMessageError < Error
20
+ end
21
+ class InvalidTagNameError < Error
22
+ end
23
+ class InvalidRejectError < Error
24
+ end
25
+ class UnknownSenderError < Error
26
+ end
27
+ class UnknownUrlError < Error
28
+ end
29
+ class UnknownTrackingDomainError < Error
30
+ end
31
+ class InvalidTemplateError < Error
32
+ end
33
+ class UnknownWebhookError < Error
34
+ end
35
+ class UnknownInboundDomainError < Error
36
+ end
37
+ class UnknownInboundRouteError < Error
38
+ end
39
+ class UnknownExportError < Error
40
+ end
41
+ class IPProvisionLimitError < Error
42
+ end
43
+ class UnknownPoolError < Error
44
+ end
45
+ class NoSendingHistoryError < Error
46
+ end
47
+ class PoorReputationError < Error
48
+ end
49
+ class UnknownIPError < Error
50
+ end
51
+ class InvalidEmptyDefaultPoolError < Error
52
+ end
53
+ class InvalidDeleteDefaultPoolError < Error
54
+ end
55
+ class InvalidDeleteNonEmptyPoolError < Error
56
+ end
57
+ class InvalidCustomDNSError < Error
58
+ end
59
+ class InvalidCustomDNSPendingError < Error
60
+ end
61
+ class MetadataFieldLimitError < Error
62
+ end
63
+ class UnknownMetadataFieldError < Error
64
+ end
65
+ end
66
+
67
+ MandrillMailer.config.api_key = ApplicationSettings.mandrill.api_key
@@ -1,6 +1,70 @@
1
1
  require 'tire/http/clients/faraday'
2
2
 
3
+ module Tire
4
+ class ExternalLogger < Tire::Logger
5
+
6
+ def initialize(logger)
7
+ @logger = logger
8
+ end
9
+
10
+ def level
11
+ @logger.level
12
+ end
13
+
14
+ def write(message)
15
+ @logger.info message
16
+ end
17
+
18
+ def log_request(endpoint, params=nil, curl='')
19
+ # 2001-02-12 18:20:42:32 [_search] (articles,users)
20
+ #
21
+ # curl -X POST ....
22
+ #
23
+ content = "# #{time}"
24
+ content += " [#{endpoint}]"
25
+ content += " (#{params.inspect})" if params
26
+ content += "\n#\n"
27
+ content += curl
28
+ content += "\n\n"
29
+ write content
30
+ end
31
+
32
+ def log_response(status, took=nil, json='')
33
+ # 2001-02-12 18:20:42:32 [200] (4 msec)
34
+ #
35
+ # {
36
+ # "took" : 4,
37
+ # "hits" : [...]
38
+ # ...
39
+ # }
40
+ #
41
+ content = "# #{time}"
42
+ content += " [#{status}]"
43
+ content += " (#{took} msec)" if took
44
+ content += "\n#\n" unless json.to_s !~ /\S/
45
+ json.to_s.each_line { |line| content += "# #{line}" } unless json.to_s !~ /\S/
46
+ content += "\n\n"
47
+ write content
48
+ end
49
+
50
+ def time
51
+ Time.now.strftime('%Y-%m-%d %H:%M:%S:%L')
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ module Tire
58
+ class Configuration
59
+ def self.logger(logger = nil)
60
+ return @logger = logger if logger
61
+ @logger || nil
62
+ end
63
+ end
64
+ end
65
+
3
66
  Tire.configure do
4
67
  url ApplicationSettings.elasticsearch.url
5
- logger Logging.logger[:elasticsearch]
6
- end
68
+ logger Tire::ExternalLogger.new(Logging.logger[:elasticsearch])
69
+ end
70
+
@@ -5,7 +5,7 @@ module DelayedJobs
5
5
  sidekiq_options unique: true
6
6
 
7
7
  def perform
8
- FayePublisher.publish('/time',Time.now.utc.to_s)
8
+ Faye::Publisher.instance.publish('/time',Time.now.utc.to_s)
9
9
  end
10
10
  end
11
11
  end
@@ -1,4 +1,4 @@
1
- require_relative 'warden/token_strategy'
1
+ require_relative '../warden/token_strategy'
2
2
 
3
3
  module Faye
4
4
  class AuthExtension
@@ -0,0 +1,57 @@
1
+ require 'connection_pool'
2
+ require 'em-synchrony/connection_pool'
3
+
4
+ module Faye
5
+ module Publisher
6
+ class << self
7
+ def instance
8
+ @default_instance ||= RedisPublisher.new(configuration.redis)
9
+ end
10
+
11
+ def configure
12
+ yield(configuration)
13
+ end
14
+
15
+ def configured?
16
+ !@config.nil?
17
+ end
18
+
19
+ private
20
+ def configuration
21
+ @config ||= OpenStruct.new(redis: {url: 'redis://localhost:6379', size: 10, namespace: 'faye'})
22
+ end
23
+ end
24
+
25
+ class RedisPublisher
26
+ def initialize(config)
27
+ case config
28
+ when
29
+ ::ConnectionPool,
30
+ EventMachine::Synchrony::ConnectionPool
31
+ @redis = config
32
+ else
33
+ @config = config
34
+ end
35
+ end
36
+
37
+ def publish(channel, payload)
38
+ redis.rpush(
39
+ 'faye.messages',
40
+ MultiJson.dump(
41
+ channel: channel,
42
+ payload: payload
43
+ )
44
+ )
45
+ end
46
+
47
+ private
48
+ def redis
49
+ @redis ||= ConnectionPool::Wrapper.new(size: @config[:size] || 10) do
50
+ connection = Redis.new(url: @config[:url])
51
+ connection = Redis::Namespace.new(@config[:namespace], redis: connection) if @config[:namespace]
52
+ connection
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ module Faye
2
+ module Publisher
3
+ FakePublishing = Struct.new(:channel, :payload)
4
+
5
+ class RedisPublisher
6
+ def publish(*args)
7
+ publishings << Faye::Publisher::FakePublishing.new(*args)
8
+ end
9
+
10
+ def clear_publishings
11
+ @publishings.clear
12
+ end
13
+
14
+ def publishings
15
+ @publishings ||= []
16
+ end
17
+ end
18
+ end
19
+ end
@@ -7,8 +7,13 @@ require 'rspec_api_documentation'
7
7
  <% if @mandrill %>
8
8
  require 'mandrill_mailer/offline'
9
9
  <% end %>
10
+
10
11
  RACK_ENV = 'test' unless defined?(RACK_ENV)
11
12
 
13
+ %w{patches}.each do |path|
14
+ Dir[File.expand_path('patches/**/*.rb', File.dirname(__FILE__))].each {|f| require f}
15
+ end
16
+
12
17
  class TestApiClient < RspecApiDocumentation::RackTestClient
13
18
  def response_body
14
19
  body = JSON.load(last_response.body)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-gen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - AMar4enko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-16 00:00:00.000000000 Z
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -106,8 +106,8 @@ files:
106
106
  - template/config/sidekiq.yml.tt
107
107
  - template/faye.ru
108
108
  - template/jobs/pong_time.rb
109
- - template/lib/faye_auth_extension.rb
110
- - template/lib/faye_publisher.rb
109
+ - template/lib/faye/auth_extension.rb
110
+ - template/lib/faye/publisher.rb
111
111
  - template/lib/mongoid/tire_plugin.rb
112
112
  - template/lib/warden/token_strategy.rb
113
113
  - template/log/.gitkeep
@@ -118,6 +118,7 @@ files:
118
118
  - template/search_indexes/user_index.rb
119
119
  - template/spec/api/mounts/auth_spec.rb.tt
120
120
  - template/spec/factories/user.rb
121
+ - template/spec/patches/faye/publisher/test.rb
121
122
  - template/spec/spec_helper.rb.tt
122
123
  - template/tmp/pids/.gitkeep
123
124
  - template/uploaders/avatar_uploader.rb
@@ -1,63 +0,0 @@
1
- require 'connection_pool'
2
- require 'em-synchrony/connection_pool'
3
-
4
- module FayePublisher
5
- FakePublishing = Struct.new(:channel, :payload)
6
- class << self
7
- def fake!
8
- @fake = true
9
- end
10
-
11
- def redis=(arg)
12
- case arg
13
- when
14
- ::ConnectionPool,
15
- EventMachine::Synchrony::ConnectionPool # Or its descendants
16
- @redis = arg
17
- else
18
- @_config = arg
19
- end
20
- end
21
-
22
- def redis
23
- @redis ||= begin
24
- config = ApplicationSettings.faye.redis
25
- ConnectionPool::Wrapper.new(size: config[:size] || 10) do
26
- connection = Redis.new(url: config[:url])
27
- connection = Redis::Namespace.new(config[:namespace], redis: connection) if config[:namespace]
28
- connection
29
- end
30
- end
31
- end
32
-
33
- def publish(channel, payload)
34
- if @fake
35
- fake_publishings.push(FakePublishing.new(channel, payload))
36
- return true
37
- end
38
- redis.rpush(
39
- 'faye.messages',
40
- MultiJson.dump(
41
- channel: channel,
42
- payload: payload
43
- )
44
- )
45
- end
46
-
47
- def configured?; @connection || @_config end
48
-
49
- def publishings
50
- raise 'FayePublisher is not configured in fake! mode' unless @fake
51
- fake_publishings
52
- end
53
-
54
- def clear_publishings
55
- @fake_publishings.clear
56
- end
57
-
58
- private
59
- def fake_publishings
60
- @fake_publishings ||= []
61
- end
62
- end
63
- end