plasticine 1.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +8 -0
- data/README.md +18 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/plasticine/base.coffee +13 -0
- data/app/assets/javascripts/plasticine/column.coffee +243 -0
- data/app/assets/javascripts/plasticine/index.js +3 -0
- data/app/assets/stylesheets/plasticine/base.scss +1 -0
- data/app/assets/stylesheets/plasticine/column.scss +44 -0
- data/app/assets/stylesheets/plasticine/index.css +4 -0
- data/app/controllers/plasticine_controller.rb +53 -0
- data/config/locales/en.yml +26 -0
- data/config/locales/fr.yml +26 -0
- data/config/routes.rb +3 -0
- data/lib/plasticine.rb +23 -0
- data/lib/plasticine/authentication.rb +43 -0
- data/lib/plasticine/base_visual.rb +11 -0
- data/lib/plasticine/builder.rb +43 -0
- data/lib/plasticine/builder/base.rb +58 -0
- data/lib/plasticine/builder/column.rb +41 -0
- data/lib/plasticine/engine.rb +7 -0
- data/lib/plasticine/helpers.rb +81 -0
- data/lib/plasticine/railtie.rb +15 -0
- data/plasticine.gemspec +22 -0
- data/spec/controllers/application_controller_spec.rb +18 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/examples_controller.rb +11 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/anonymou.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +18 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +5 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/standard_rails_initializers.rb +9 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/plasticine/base_spec.rb +7 -0
- data/spec/plasticine_spec.rb +4 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/views_helper.rb +12 -0
- data/vendor/assets/javascripts/d3.js +6 -0
- metadata +191 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
en:
|
2
|
+
date:
|
3
|
+
formats:
|
4
|
+
plasticine_date_without_day: "%B %Y"
|
5
|
+
plasticine_date_long: "%e %B %Y"
|
6
|
+
plasticine_date_long_without_year: "%e %B"
|
7
|
+
plasticine_day: "%e"
|
8
|
+
plasticine_year: "%Y"
|
9
|
+
|
10
|
+
plasticine:
|
11
|
+
base:
|
12
|
+
steps:
|
13
|
+
day: Day
|
14
|
+
week: Week
|
15
|
+
month: Month
|
16
|
+
quarter: Quarter
|
17
|
+
year: Year
|
18
|
+
|
19
|
+
time:
|
20
|
+
formats:
|
21
|
+
plasticine_date_without_day: "%B %Y"
|
22
|
+
plasticine_date_long: "%B %e, %Y"
|
23
|
+
plasticine_date_long_without_year: "%e %B"
|
24
|
+
plasticine_day: "%e"
|
25
|
+
plasticine_long: "%B %d, %Y %H:%M"
|
26
|
+
plasticine_year: "%Y"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
fr:
|
2
|
+
date:
|
3
|
+
formats:
|
4
|
+
plasticine_date_without_day: "%B %Y"
|
5
|
+
plasticine_date_long: "%e %B %Y"
|
6
|
+
plasticine_date_long_without_year: "%e %B"
|
7
|
+
plasticine_day: "%e"
|
8
|
+
plasticine_year: "%Y"
|
9
|
+
|
10
|
+
plasticine:
|
11
|
+
base:
|
12
|
+
steps:
|
13
|
+
day: Jour
|
14
|
+
week: Semaine
|
15
|
+
month: Mois
|
16
|
+
quarter: Trimestre
|
17
|
+
year: Année
|
18
|
+
|
19
|
+
time:
|
20
|
+
formats:
|
21
|
+
plasticine_date_without_day: "%B %Y"
|
22
|
+
plasticine_date_long: "%e %B %Y"
|
23
|
+
plasticine_date_long_without_year: "%e %B"
|
24
|
+
plasticine_day: "%e"
|
25
|
+
plasticine_long: "%e %B %Y à %H:%M"
|
26
|
+
plasticine_year: "%Y"
|
data/config/routes.rb
ADDED
data/lib/plasticine.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Plasticine
|
2
|
+
def self.localize(path, options={})
|
3
|
+
options.reverse_merge! format: :date_long
|
4
|
+
|
5
|
+
options[:format] = "plasticine_#{options[:format]}".to_sym
|
6
|
+
|
7
|
+
return I18n.localize(path, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.translate(path, options={})
|
11
|
+
I18n.translate("plasticine.#{path}", options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.t(path, options={})
|
15
|
+
self.translate path, options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require "plasticine/authentication"
|
20
|
+
require "plasticine/base_visual"
|
21
|
+
require "plasticine/builder"
|
22
|
+
require "plasticine/engine"
|
23
|
+
require "plasticine/railtie"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Plasticine
|
4
|
+
class Authentication
|
5
|
+
|
6
|
+
def initialize(request_url, params={})
|
7
|
+
@request_url = request_url
|
8
|
+
@params = params
|
9
|
+
end
|
10
|
+
|
11
|
+
def expired?
|
12
|
+
@params[:timestamp] and Time.parse(@params[:timestamp]) + 12.hours < Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid_token?
|
16
|
+
@params[:token] == tokenize
|
17
|
+
end
|
18
|
+
|
19
|
+
def tokenize
|
20
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, token_key, filtered_url)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def compacted_params
|
27
|
+
@params.map{ |k,v| "#{k}#{v}" if not reserved_params.include?(k.to_s) }.join
|
28
|
+
end
|
29
|
+
|
30
|
+
def filtered_url
|
31
|
+
url = @request_url.split('?').first.rpartition('/').first + compacted_params
|
32
|
+
url.chars.sort.join.gsub('/', '')
|
33
|
+
end
|
34
|
+
|
35
|
+
def reserved_params
|
36
|
+
['action', 'class', 'controller', 'format', 'from', 'nature', 'step', 'to', 'token', 'tools', 'update_every', 'version']
|
37
|
+
end
|
38
|
+
|
39
|
+
def token_key
|
40
|
+
Rails.application.config.secret_key_base
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Plasticine::Builder
|
2
|
+
def self.period(start_at, end_at, options={})
|
3
|
+
options.reverse_merge!(step: 'day')
|
4
|
+
|
5
|
+
start_at_format = case
|
6
|
+
when options[:step] == 'month' then :date_without_day
|
7
|
+
when options[:step] == 'year' then :year
|
8
|
+
when start_at.year != end_at.year then :date_long
|
9
|
+
when start_at.month != end_at.month then :date_long_without_year
|
10
|
+
else :day
|
11
|
+
end
|
12
|
+
|
13
|
+
end_at_format = case options[:step]
|
14
|
+
when 'month' then :date_without_day
|
15
|
+
when 'year' then :year
|
16
|
+
else :date_long
|
17
|
+
end
|
18
|
+
|
19
|
+
content = []
|
20
|
+
content << Plasticine.localize(start_at, format: start_at_format)
|
21
|
+
content << (['month', 'year'].include?(options[:step]) ? Plasticine.t('date.period.to_month') : Plasticine.t('date.period.to'))
|
22
|
+
content << Plasticine.localize(end_at, format: end_at_format)
|
23
|
+
|
24
|
+
content[0].capitalize!
|
25
|
+
|
26
|
+
return content.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.get_step_from_interval(interval)
|
30
|
+
days = (interval / (3600 * 24)).to_i.abs
|
31
|
+
|
32
|
+
return case days
|
33
|
+
when 0..5 then 'day'
|
34
|
+
when 6..27 then 'week'
|
35
|
+
when 28..88 then 'month'
|
36
|
+
when 89..363 then 'quarter'
|
37
|
+
else 'year'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'plasticine/builder/base'
|
43
|
+
require 'plasticine/builder/column'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Plasticine::Builder::Base
|
2
|
+
attr_accessor :visual
|
3
|
+
|
4
|
+
def initialize(id, options={})
|
5
|
+
options.reverse_merge! from: nil, to: nil, step: nil
|
6
|
+
|
7
|
+
@from = options[:from] ? Time.parse(options[:from]) : nil
|
8
|
+
@to = options[:to] ? Time.parse(options[:to]) : Time.now
|
9
|
+
|
10
|
+
@visual = { id: id }
|
11
|
+
@visual[:step] = options[:step] if options[:step]
|
12
|
+
@visual[:title] = t('title')
|
13
|
+
@visual[:period] = Plasticine::Builder.period(@from, @to, step: @visual[:step]) if @from
|
14
|
+
end
|
15
|
+
|
16
|
+
def close_visual
|
17
|
+
# Hooks before closing a visual
|
18
|
+
end
|
19
|
+
|
20
|
+
def id
|
21
|
+
@visual[:id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def l(date, options={})
|
25
|
+
options.reverse_merge!(format: :date_long)
|
26
|
+
|
27
|
+
Plasticine.localize(date, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def period
|
31
|
+
@visual[:period]
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_period_from_data(data)
|
35
|
+
@from = data.first
|
36
|
+
@to = data.last
|
37
|
+
|
38
|
+
@visual[:step] = Plasticine::Builder.get_step_from_interval(data[1] - data[0]) if not @visual[:step]
|
39
|
+
|
40
|
+
@visual[:period] = Plasticine::Builder.period @from, @to, step: @visual[:step]
|
41
|
+
end
|
42
|
+
|
43
|
+
def t(path, vars={})
|
44
|
+
vars.reverse_merge! default: ''
|
45
|
+
|
46
|
+
Plasticine.translate("#{id.gsub('-', '_')}.#{path}", vars)
|
47
|
+
end
|
48
|
+
|
49
|
+
def title
|
50
|
+
@visual[:title]
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_json
|
54
|
+
close_visual
|
55
|
+
|
56
|
+
@visual.to_json
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Plasticine::Builder::Column < Plasticine::Builder::Base
|
2
|
+
def initialize(id, options={})
|
3
|
+
super
|
4
|
+
|
5
|
+
@visual.merge! columns: [], nature: 'column', axis_x_format: :string, axis_y_format: :number, axis_y_tick_count: 10, quarter_start_month: 1
|
6
|
+
@columns = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_column(x, y, options={})
|
10
|
+
options.reverse_merge! tooltip: nil
|
11
|
+
|
12
|
+
@columns[x] = [] if not @columns[x]
|
13
|
+
|
14
|
+
@columns[x] << { tooltip: options[:tooltip], y: y }
|
15
|
+
end
|
16
|
+
|
17
|
+
def axis_x_format=(format)
|
18
|
+
@visual[:axis_x_format] = format
|
19
|
+
end
|
20
|
+
|
21
|
+
def axis_y_format=(format)
|
22
|
+
@visual[:axis_y_format] = format
|
23
|
+
end
|
24
|
+
|
25
|
+
def axis_y_tick_count=(tick_count)
|
26
|
+
@visual[:axis_y_tick_count] = tick_count
|
27
|
+
end
|
28
|
+
|
29
|
+
def quarter_start_month=(month)
|
30
|
+
@visual[:quarter_start_month] = month
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def close_visual
|
35
|
+
super
|
36
|
+
|
37
|
+
@columns.each do |x, data|
|
38
|
+
@visual[:columns] << { x_value: x, y_values: data.map{ |d| d[:y] }, tooltip: data[0][:tooltip] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Plasticine
|
2
|
+
#*************************************************************************************
|
3
|
+
# Make the gem behave as an engine.
|
4
|
+
#*************************************************************************************
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Plasticine::Helpers
|
2
|
+
def d3_include_tag
|
3
|
+
('<![if ! lt IE 9]>' + javascript_include_tag("d3") + '<![endif]>').html_safe
|
4
|
+
end
|
5
|
+
|
6
|
+
def column_visual(id, options={})
|
7
|
+
PlasticineTagHelper.new(self, id, options[:from], options[:to], options[:step]).column(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class PlasticineTagHelper
|
12
|
+
attr_reader :rails_helpers
|
13
|
+
|
14
|
+
delegate :content_tag, to: :rails_helpers
|
15
|
+
delegate :link_to, to: :rails_helpers
|
16
|
+
delegate :plasticine_url, to: :rails_helpers
|
17
|
+
|
18
|
+
def initialize(rails_helpers, id, from, to, step)
|
19
|
+
@rails_helpers = rails_helpers
|
20
|
+
@id = id
|
21
|
+
@from = from
|
22
|
+
@to = to
|
23
|
+
@step = step || 'month'
|
24
|
+
end
|
25
|
+
|
26
|
+
def column(options={})
|
27
|
+
options.reverse_merge! columns_left_padding: 20, columns_right_padding: 20, columns_margin: 0.2, y_spacing_ratio: 1.10
|
28
|
+
|
29
|
+
options[:data] = {
|
30
|
+
columns_left_padding: options.delete(:columns_left_padding),
|
31
|
+
columns_right_padding: options.delete(:columns_right_padding),
|
32
|
+
columns_margin: options.delete(:columns_margin),
|
33
|
+
y_spacing_ratio: options.delete(:y_spacing_ratio)
|
34
|
+
}
|
35
|
+
|
36
|
+
visual 'column', options
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def build_url(nature, options={})
|
43
|
+
params = { from: @from, format: 'json', id: @id, nature: nature, nonce: SecureRandom.hex(20), step: @step, timestamp: Time.now.utc.iso8601, to: @to, version: 'v1' }
|
44
|
+
|
45
|
+
options.each { |k,v| params[k] = v if not ['class', 'data', 'tools'].include? k.to_s }
|
46
|
+
|
47
|
+
params[:token] = build_url_token(params)
|
48
|
+
|
49
|
+
@url = plasticine_url(params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_url_token(params)
|
53
|
+
base_url = plasticine_url(id: params[:id])
|
54
|
+
authentificator = Plasticine::Authentication.new(base_url, params)
|
55
|
+
authentificator.tokenize
|
56
|
+
end
|
57
|
+
|
58
|
+
def t(path)
|
59
|
+
Plasticine.translate(path)
|
60
|
+
end
|
61
|
+
|
62
|
+
def visual(nature, options={})
|
63
|
+
options.reverse_merge! class: "", data: {}
|
64
|
+
|
65
|
+
options[:class] += " plasticine plasticine-#{nature}"
|
66
|
+
|
67
|
+
build_url nature, options
|
68
|
+
|
69
|
+
options[:data][:visual] = nature
|
70
|
+
options[:data][:url] = @url
|
71
|
+
options[:data][:update_delay] = options[:update_every].to_i if options[:update_every]
|
72
|
+
|
73
|
+
content = content_tag(:div, '', id: @id, class: options[:class], data: options[:data])
|
74
|
+
content << link_to(@url, @url)
|
75
|
+
|
76
|
+
content
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
::ActionView::Base.send :include, self
|
81
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Plasticine
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer "plasticine" do |app|
|
4
|
+
ActiveSupport.on_load :action_view do
|
5
|
+
require 'plasticine/helpers'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
12
|
+
languages = [:fr, :en]
|
13
|
+
|
14
|
+
I18n.load_path += languages.map { |l| File.join(dir, '../../config/locales', "#{l}.yml") }
|
15
|
+
|
data/plasticine.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = "plasticine"
|
3
|
+
gem.description = "Data visualization toolkit for Rails App using D3.js"
|
4
|
+
gem.summary = "Data visualization toolkit for Rails App using D3.js"
|
5
|
+
gem.homepage = "https://github.com/alchimikweb/plasticine"
|
6
|
+
gem.version = "1.1.0"
|
7
|
+
gem.licenses = ["MIT"]
|
8
|
+
|
9
|
+
gem.authors = ["Sebastien Rosa"]
|
10
|
+
gem.email = ["sebastien@alchimik.com"]
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
|
17
|
+
gem.add_dependency "rails", ['~> 5.0']
|
18
|
+
gem.add_development_dependency "sqlite3", "~> 1.3"
|
19
|
+
gem.add_development_dependency "rspec-rails", "~> 3.7"
|
20
|
+
gem.add_development_dependency "simplecov", "~> 0.15"
|
21
|
+
gem.add_development_dependency "simplecov-rcov-text", "~> 0"
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ApplicationController, type: :controller do
|
4
|
+
controller do
|
5
|
+
def index
|
6
|
+
render plain: 'Done'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "when calling index action" do
|
11
|
+
it 'should be done' do
|
12
|
+
get :index
|
13
|
+
|
14
|
+
expect(response.status).to eq(200)
|
15
|
+
expect(response.body).to eq "Done"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/dummy/Rakefile
ADDED