dech 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e75dc0ac05d00fe019e35c471e4d8bf99d987499
4
- data.tar.gz: c373618bf25961474e9812a1c204ffa74dc34419
3
+ metadata.gz: 558691d6d3a193e1034f53c757653d8b445e0ce1
4
+ data.tar.gz: 7eff60d509fe99172ec652dec658b41af0b60541
5
5
  SHA512:
6
- metadata.gz: a19d46d53d061d34999c4f2506a797ade35cc7f148fbf0dc36d7ec3830460017db6013128a788eac0c89456cf6272a4c371d65ade4f5fbab0bd3cf43bd9c24a5
7
- data.tar.gz: bd39eb4c5f5775afc549ee875a696b2761e335e8be352997a4b6be2cd6645561d792fad4ae56a7cd1147a0122e94378c64ebf1e64af12ca7fb4e4c6cee367d0e
6
+ metadata.gz: 1532a2a6c9daa0005fc6b937304b8bf4e450da8117e144f3064d0592fbe0bca1344fc98e1a18c2b23197c0b71469d235936142a224ca5d8226f241c53e064ffc
7
+ data.tar.gz: dfbc97fc9eb0673f8f770abc13217a98695a31fda768a23d26b77edb5c457819f99de71bf40b84eee48eccccfc831882545ad3e44e26530d3def468980692438
data/.rspec CHANGED
@@ -1 +1 @@
1
- --color
1
+ --color --format doc
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["OSA Shunsuke"]
10
10
  spec.email = ["hhelibebcnofnenamg@gmail.com"]
11
11
  spec.summary = %q{Utilities gem for e-commerce mall in Japan.}
12
- spec.description = %q{Dech enables you to upload price change easily.}
12
+ spec.description = %q{Dech enables to upload product information easily.}
13
13
  spec.homepage = "https://github.com/e-maido/dech"
14
14
  spec.license = "MIT"
15
15
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "double-bag-ftps"
22
+ spec.add_dependency "emmental"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.5"
24
25
  spec.add_development_dependency "rake"
@@ -1,8 +1,13 @@
1
1
  # coding: utf-8
2
2
 
3
+ require "dech/hash_key_mapper"
3
4
  require "dech/version"
4
- require "dech/csvio"
5
+
6
+ require "dech/rakuten"
7
+
8
+ # deprecated classes
5
9
  require "dech/price_uploader"
10
+ require "dech/csvio"
6
11
 
7
12
  module Dech
8
13
  end
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+
3
+ require 'csv'
4
+ require 'stringio'
5
+
6
+ module Dech
7
+ class CSV < StringIO
8
+ DEFAULT_ENCODING = Encoding::Windows_31J
9
+
10
+ def initialize(array, args={})
11
+ @array = array
12
+ @option = {}
13
+ @option[:headers] = args[:headers] != false
14
+ @option[:encoding] = args[:encoding] || DEFAULT_ENCODING
15
+ super(csv_string)
16
+ end
17
+
18
+ def headers
19
+ @option[:headers] ? @array.first : nil
20
+ end
21
+
22
+ def save_as(path)
23
+ FileUtils.mkdir_p(File.dirname(path))
24
+ File.open(path, [:w, @option[:encoding].name].join(":")){|file| file << csv_string }
25
+ end
26
+
27
+ def to_a
28
+ @array
29
+ end
30
+
31
+ def to_s
32
+ csv_string
33
+ end
34
+
35
+ private
36
+
37
+ def csv_string
38
+ ::CSV.generate{|csv| @array.each{|row| csv << row } }.encode(@option[:encoding])
39
+ end
40
+ end
41
+ end
@@ -7,7 +7,7 @@ module Dech
7
7
  class CSVIO < StringIO
8
8
  class << self
9
9
  def generate(args={})
10
- csv_string = CSV.generate{|csv| yield(csv) if block_given? }
10
+ csv_string = ::CSV.generate{|csv| yield(csv) if block_given? }
11
11
  self.new(csv_string.encode(args[:encoding] || Encoding::Windows_31J))
12
12
  end
13
13
  end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ module Dech
4
+ class HashKeyMapper
5
+ class << self
6
+ def map(hash, mapping)
7
+ new(hash, mapping).map
8
+ end
9
+ end
10
+
11
+ def initialize(hash={}, mapping={})
12
+ @hash = hash
13
+ @mapping = mapping
14
+ end
15
+
16
+ def map
17
+ new_hash = {}
18
+ @hash.each do |k, v|
19
+ [@mapping[k] || k].flatten.each do |new_key|
20
+ new_hash[new_key] = v
21
+ end
22
+ end
23
+ new_hash
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+ require 'dech/rakuten/ftp'
3
+
4
+ module Dech
5
+ class Rakuten
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+ require 'emmental'
3
+ require 'dech/csv'
4
+ require 'dech/hash_key_mapper'
5
+
6
+ module Dech
7
+ class Rakuten
8
+ class CSV < Dech::CSV
9
+ ENCODING = Encoding::Windows_31J
10
+
11
+ HEADER_MAPPINGS = {
12
+ id: "商品管理番号(商品URL)",
13
+ price: "販売価格"
14
+ }
15
+
16
+ REQUIRED_HEADERS = [
17
+ "コントロールカラム",
18
+ "商品管理番号(商品URL)"
19
+ ]
20
+
21
+ STATIC_COLUMNS = {"コントロールカラム" => "u"}
22
+
23
+ def initialize(products)
24
+ @products = products
25
+ super(formatted_products)
26
+ end
27
+
28
+ def valid?
29
+ validate! rescue false
30
+ end
31
+
32
+ def validate!
33
+ translated_products.each do |product|
34
+ REQUIRED_HEADERS.each do |header|
35
+ raise "#{header} is missing in #{product}" unless product.keys.include?(header)
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def formatted_products
43
+ emmental = Emmental.new
44
+ translated_products.each{|product| emmental << product }
45
+ emmental.to_a
46
+ end
47
+
48
+ def translated_products
49
+ merged_products.map{|product| Dech::HashKeyMapper.map(product, HEADER_MAPPINGS) }
50
+ end
51
+
52
+ def merged_products
53
+ @products.map{|product| STATIC_COLUMNS.merge(product) }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ require 'net/ftp'
3
+ require 'dech/rakuten/csv'
4
+
5
+ module Dech
6
+ class Rakuten
7
+ class FTP
8
+ DEFAULT_HOST = "upload.rakuten.ne.jp"
9
+ DEFAULT_PATH = "/ritem/batch/item.csv"
10
+
11
+ attr_accessor :products, :username, :host, :path
12
+
13
+ def initialize(args={})
14
+ @products = args[:products] || []
15
+ @username = args[:username]
16
+ @password = args[:password]
17
+ @host = args[:host] || DEFAULT_HOST
18
+ @path = args[:path] || DEFAULT_PATH
19
+ end
20
+
21
+ def csv
22
+ Dech::Rakuten::CSV.new(@products)
23
+ end
24
+
25
+ def ready?
26
+ ftp_connection{|ftp| !ftp.nlst(File.dirname(@path)).include?(@path) }
27
+ end
28
+
29
+ def upload!
30
+ ftp_connection{|ftp| ftp.storlines("STOR #{@path}", csv) }
31
+ true
32
+ end
33
+
34
+ def upload
35
+ ready? && upload!
36
+ end
37
+
38
+ private
39
+
40
+ def ftp_connection
41
+ Net::FTP.open(@host, @username, @password){|ftp| yield(ftp) }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Dech
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.4"
5
5
  end
@@ -0,0 +1,94 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::CSV do
5
+ describe "initialize" do
6
+ describe "class" do
7
+ subject{ Dech::CSV.new([]) }
8
+ it { is_expected.to be_a(StringIO) }
9
+ it { is_expected.to be_an_instance_of(Dech::CSV) }
10
+ end
11
+
12
+ describe "options" do
13
+ describe "encoding" do
14
+ context :default do
15
+ subject{ Dech::CSV.new([]).external_encoding }
16
+ it { is_expected.to be(Encoding::Windows_31J) }
17
+ end
18
+
19
+ context :given, Encoding::UTF_8 do
20
+ subject{ Dech::CSV.new([], encoding: Encoding::UTF_8).external_encoding }
21
+ it { is_expected.to be(Encoding::UTF_8) }
22
+ end
23
+ end
24
+
25
+ describe "headers" do
26
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
27
+
28
+ context "default with", array.first do
29
+ subject{ Dech::CSV.new(array).headers }
30
+ it { is_expected.to eq(array.first) }
31
+ end
32
+
33
+ context "given false with", array.first do
34
+ subject{ Dech::CSV.new(array, headers: false).headers }
35
+ it { is_expected.to eq(nil) }
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#to_a" do
42
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
43
+ subject{ Dech::CSV.new(array).to_a }
44
+
45
+ it { is_expected.to be_an_instance_of(Array) }
46
+
47
+ context :given, array do
48
+ it { is_expected.to eq(array) }
49
+ end
50
+ end
51
+
52
+ describe "#to_s" do
53
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
54
+ subject{ Dech::CSV.new(array).to_s }
55
+
56
+ it { is_expected.to be_an_instance_of(String) }
57
+
58
+ context :given, array do
59
+ array.each do |row|
60
+ row.each do |cell|
61
+ it { is_expected.to include(cell.to_s) }
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#save_as(path)" do
68
+ let(:dirname) { "tmp" }
69
+ let(:filename){ "#{Time.now.strftime("%Y%m%d_%H%M%S_%N")}.csv" }
70
+ let(:path) { File.join(dirname, filename) }
71
+ subject{ lambda{ Dech::CSV.new([]).save_as(path) } }
72
+
73
+ it { is_expected.to change{Dir.glob(File.join(dirname, "*")).size}.by(1) }
74
+
75
+ describe "saved file" do
76
+ before { subject.call }
77
+
78
+ it "should exist" do
79
+ expect(Dir.glob(File.join(dirname, "*"))).to include(path)
80
+ end
81
+
82
+ it "should be valid CSV" do
83
+ CSV.open(path, "r:windows-31j:utf-8", headers: true) do |csv|
84
+ expect{csv.readlines}.not_to raise_error
85
+ end
86
+ end
87
+ end
88
+
89
+ after do
90
+ files = Dir.glob(File.join(dirname, "*"))
91
+ FileUtils.remove(files)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,46 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::HashKeyMapper do
5
+ describe "class methods" do
6
+ describe ".map" do
7
+ it "should call #{described_class}#map" do
8
+ hash = {}
9
+ mapping = {}
10
+
11
+ mapper = double("mapper")
12
+ expect(mapper).to receive(:map)
13
+ expect(described_class).to receive(:new).with(hash, mapping).and_return(mapper)
14
+
15
+ described_class.map(hash, mapping)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "initialize" do
21
+ subject{ described_class.new }
22
+ it { is_expected.to be_an_instance_of(described_class) }
23
+ end
24
+
25
+ describe "#map" do
26
+ context "1 key to 1 key" do
27
+ hash = {foo: "foo", bar: "bar", fizz: "fizz"}
28
+ mapping = {foo: "FOO", fizz: "FIZZ"}
29
+
30
+ subject{ described_class.new(hash, mapping).map }
31
+ it "should rename a key" do
32
+ is_expected.to eq({"FOO" => "foo", bar: "bar", "FIZZ" => "fizz"})
33
+ end
34
+ end
35
+
36
+ context "1 key to n keys" do
37
+ hash = {foo: "foo", bar: "bar", fizz: "fizz"}
38
+ mapping = {foo: ["FOO", "Foo"], fizz: "FIZZ"}
39
+
40
+ subject{ described_class.new(hash, mapping).map }
41
+ it "should remove a old key and add new keys" do
42
+ is_expected.to eq({"FOO" => "foo", "Foo" => "foo", bar: "bar", "FIZZ" => "fizz"})
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::Rakuten::CSV do
5
+ describe "initialize" do
6
+ products = [
7
+ {id: "ABC-001", price: 12800},
8
+ {id: "xyz-123", price: 9800}
9
+ ]
10
+
11
+ subject{ Dech::Rakuten::CSV.new(products) }
12
+ it { is_expected.to be_an_instance_of(Dech::Rakuten::CSV) }
13
+ it { is_expected.to be_a(Dech::CSV) }
14
+ it { is_expected.to be_a(StringIO) }
15
+
16
+ p Dech::Rakuten::CSV.new(products).to_a
17
+ end
18
+
19
+ describe "#valid?" do
20
+ context "with valid columns" do
21
+ products = [
22
+ {id: "ABC-001", price: 12800},
23
+ {id: "xyz-123", price: 9800}
24
+ ]
25
+
26
+ subject{ Dech::Rakuten::CSV.new(products) }
27
+ it { is_expected.to be_valid }
28
+ end
29
+
30
+ context "with invalid columns" do
31
+ products = [
32
+ {price: 12800},
33
+ {price: 9800}
34
+ ]
35
+
36
+ subject{ Dech::Rakuten::CSV.new(products) }
37
+ it { is_expected.not_to be_valid }
38
+ end
39
+ end
40
+
41
+ describe "#validate!" do
42
+ context "valid columns" do
43
+ products = [
44
+ {id: "ABC-001", price: 12800},
45
+ {id: "xyz-123", price: 9800}
46
+ ]
47
+
48
+ subject{ lambda{ Dech::Rakuten::CSV.new(products).validate! } }
49
+ it { is_expected.not_to raise_error }
50
+ end
51
+
52
+ context "invalid columns" do
53
+ products = [
54
+ {price: 12800},
55
+ {price: 9800}
56
+ ]
57
+
58
+ subject{ lambda{ Dech::Rakuten::CSV.new(products).validate! } }
59
+ it { is_expected.to raise_error }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,93 @@
1
+ # coding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Dech::Rakuten::FTP do
6
+ let(:ftp) {
7
+ described_class.new(
8
+ products: [{id: "PRODUCT-CODE", price: 9800}],
9
+ username: "username",
10
+ password: "password",
11
+ host: "example.com"
12
+ )
13
+ }
14
+
15
+ let(:net_ftp) {
16
+ net_ftp = double("net_ftp")
17
+ allow(net_ftp).to receive(:passive=)
18
+ allow(net_ftp).to receive(:connect)
19
+ allow(net_ftp).to receive(:login)
20
+ allow(net_ftp).to receive(:close)
21
+ expect(Net::FTP).to receive(:new).and_return(net_ftp)
22
+ net_ftp
23
+ }
24
+
25
+ describe "initialize" do
26
+ subject { ftp }
27
+ it { is_expected.to be_an_instance_of(described_class) }
28
+ end
29
+
30
+ describe "#csv" do
31
+ subject { ftp.csv }
32
+ it { is_expected.to be_an_instance_of(Dech::Rakuten::CSV) }
33
+ end
34
+
35
+ describe "#ready?" do
36
+ subject { ftp.ready? }
37
+
38
+ context "CSV file exists in FTP server" do
39
+ before { expect(net_ftp).to receive(:nlst).and_return([ftp.path]) }
40
+ it { is_expected.to be false }
41
+ end
42
+
43
+ context "CSV file does not exist in FTP server" do
44
+ before { expect(net_ftp).to receive(:nlst).and_return([]) }
45
+ it { is_expected.to be true }
46
+ end
47
+ end
48
+
49
+ describe "#upload!" do
50
+ subject{ lambda{ ftp.upload! } }
51
+
52
+ it "should upload CSV file to the path on FTP server" do
53
+ expect(net_ftp).to receive(:storlines)
54
+ subject.call
55
+ end
56
+ end
57
+
58
+ =begin
59
+ describe "#upload" do
60
+ context "server is ready" do
61
+ before do
62
+ allow(ftp).to receive(:nlst).and_return([])
63
+ expect(ftp).to receive(:storlines)
64
+ expect(Net::FTP).to receive(:new).and_return(ftp).at_least(:once)
65
+ end
66
+
67
+ it "should upload CSV file to the path on FTP server" do
68
+ expect(dech.upload).to be true
69
+ end
70
+ end
71
+ end
72
+ =end
73
+
74
+ describe "#upload" do
75
+ subject{ lambda{ ftp.upload } }
76
+
77
+ context "FTP server is ready" do
78
+ it "should call #upload!" do
79
+ expect(ftp).to receive(:ready?).and_return(true)
80
+ expect(ftp).to receive(:upload!).and_return(true)
81
+ subject.call
82
+ end
83
+ end
84
+
85
+ context "FTP server is not ready" do
86
+ it "should not call #upload!" do
87
+ expect(ftp).to receive(:ready?).and_return(false)
88
+ expect(ftp).not_to receive(:upload!)
89
+ subject.call
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::Rakuten do
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dech
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - OSA Shunsuke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-21 00:00:00.000000000 Z
11
+ date: 2014-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: double-bag-ftps
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: emmental
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +94,7 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
- description: Dech enables you to upload price change easily.
97
+ description: Dech enables to upload product information easily.
84
98
  email:
85
99
  - hhelibebcnofnenamg@gmail.com
86
100
  executables: []
@@ -97,16 +111,26 @@ files:
97
111
  - Rakefile
98
112
  - dech.gemspec
99
113
  - lib/dech.rb
114
+ - lib/dech/csv.rb
100
115
  - lib/dech/csvio.rb
116
+ - lib/dech/hash_key_mapper.rb
101
117
  - lib/dech/price_uploader.rb
102
118
  - lib/dech/price_uploader/dena.rb
103
119
  - lib/dech/price_uploader/dena/ftp.rb
104
120
  - lib/dech/price_uploader/ponpare.rb
105
121
  - lib/dech/price_uploader/ponpare/ftps.rb
122
+ - lib/dech/rakuten.rb
123
+ - lib/dech/rakuten/csv.rb
124
+ - lib/dech/rakuten/ftp.rb
106
125
  - lib/dech/version.rb
126
+ - spec/dech/csv_spec.rb
107
127
  - spec/dech/csvio_spec.rb
128
+ - spec/dech/hash_key_mapper_spec.rb
108
129
  - spec/dech/price_uploader/dena/ftp_spec.rb
109
130
  - spec/dech/price_uploader/ponpare/ftps_spec.rb
131
+ - spec/dech/rakuten/csv_spec.rb
132
+ - spec/dech/rakuten/ftp_spec.rb
133
+ - spec/dech/rakuten_spec.rb
110
134
  - spec/dech_spec.rb
111
135
  - spec/spec_helper.rb
112
136
  homepage: https://github.com/e-maido/dech
@@ -134,8 +158,13 @@ signing_key:
134
158
  specification_version: 4
135
159
  summary: Utilities gem for e-commerce mall in Japan.
136
160
  test_files:
161
+ - spec/dech/csv_spec.rb
137
162
  - spec/dech/csvio_spec.rb
163
+ - spec/dech/hash_key_mapper_spec.rb
138
164
  - spec/dech/price_uploader/dena/ftp_spec.rb
139
165
  - spec/dech/price_uploader/ponpare/ftps_spec.rb
166
+ - spec/dech/rakuten/csv_spec.rb
167
+ - spec/dech/rakuten/ftp_spec.rb
168
+ - spec/dech/rakuten_spec.rb
140
169
  - spec/dech_spec.rb
141
170
  - spec/spec_helper.rb