1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<!DOCTYPE html> <meta charset="utf-8"> <style> body { margin: 0; background: #222; min-width: 960px; } rect { fill: none; pointer-events: all; } circle { fill: none; stroke-width: 2.5px; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script>window.d3 || document.write('<script src="d3.min.js"><\/script>')</script> <script> var width = Math.max(960, innerWidth), height = Math.max(500, innerHeight); var i = 0; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); svg.append("rect") .attr("width", width) .attr("height", height) .on("ontouchstart" in document ? "touchmove" : "mousemove", particle); function particle() { var m = d3.mouse(this); svg.insert("circle", "rect") .attr("cx", m[0]) .attr("cy", m[1]) .attr("r", 1e-6) .style("stroke", d3.hsl((i = (i + 1) % 360), 1, .5)) .style("stroke-opacity", 1) .transition() .duration(2000) .ease(Math.sqrt) .attr("r", 100) .style("stroke-opacity", 1e-6) .remove(); d3.event.preventDefault(); } </script> |
C# Webサーバー
サーバ1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
using System; using System.Windows.Forms; namespace tcp_listen_client { public partial class Form1 : Form { public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; //スレッドからテキストボックスにアクセスすることを許可 //スレッドセーフとはアプリをマルチスレッドで走らせても問題ないこと。 //Formはスレッドセーフではない。 //通常、Control はメンバの参照時にUIスレッド(Application.Run したスレッド)で操作することを強制。 //CheckForIllegalCrossThreadCallsをfalseにすると、これを回避できる。 } private System.Net.Sockets.TcpListener server;//リスナー接続待ちや受信等を行うオブジェクト private System.Threading.Thread ListeningCallbackThred;//接続待ちスレッド private volatile bool SLTAlive;//接続待ちスレッド終了指示フラグ //volatile //複数のスレッドによって変更される可能性がある場合指定。 //シングルスレット前提の最適化をしない private void Form1_Load(object sender, EventArgs e) { this.Text = "サーバー"; button1.Text = "サーバー開始"; button2.Text = "サーバー終了"; label1.Text = ""; SLTAlive = false; //スレッド終了指示フラグを終了に初期化 } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { //サーバーを終了するのに、接続待ちスレッドが終了していない場合 if (SLTAlive) { SLTAlive = false; server.Stop(); ListeningCallbackThred = null; //スレッドをnull設定 } } private void button1_Click(object sender, EventArgs e) { //接続待ちスレッドが生成されていない場合 if (!SLTAlive) { ListeningCallbackThred = new System.Threading.Thread(ListeningCallback); //ListeningCallbackはメソッド ListeningCallbackThred.Start(); SLTAlive = true; //未終了に設定 } } private void button2_Click(object sender, EventArgs e) { if (SLTAlive) { if (server != null) { server.Stop(); } } SLTAlive = false;//終了に設定 label1.Text = "サーバー終了"; } private void ListeningCallback() { //リスナーを生成 server = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Parse("192.168.102.9"),9000); server.Start(); label1.Text = "サーバー開始"; try { //受信は無限ループ。終了指示があればループ終了 while (SLTAlive) { //受信接続キューに接続待ちがあるかどうか if(server.Pending() == true) { //クライアントからの接続を受け付ける。 //通信ストリームの取得 System.Net.Sockets.TcpClient ClientSocket = server.AcceptTcpClient(); System.Net.Sockets.NetworkStream stream = ClientSocket.GetStream(); byte[] ReceiveData = new byte[2000]; int DataLength = stream.Read(ReceiveData,0,ReceiveData.Length); // textBox1.Text = ReceiveData.ToString(); こうすると // System.Byte[]と表示される。つまりバイト型の配列になっているということか。 //string str = System.Text.Encoding.ASCII.GetString(ReceiveData, 0, DataLength); string str = System.Text.Encoding.GetEncoding("shift_jis").GetString(ReceiveData,0,DataLength); //GETのパラメータに日本語を入れてリクエストした場合、 //ASCIIだと??となる。 //UTF-8だと文字化けする。 //shift_jisでちゃんと表示された。 //str = Uri.UnescapeDataString(str); // String <- byte[] GetString // String -> byte[] GetByte textBox1.Text = str; //返信 string html = "<a href=\"http://yahoo.co.jp\">hello</a>"; byte[] SendBuffer = System.Text.Encoding.ASCII.GetBytes(html); //ASCIの部分をUnicodeにするとブラウザでダウロードしてしまう。 stream.Write(SendBuffer, 0, SendBuffer.Length); //stream.Flush(); ClientSocket.Close(); } //短時間だけ待機 System.Threading.Thread.Sleep(100); } } catch(Exception e) { label1.Text = "サーバー終了"; } } } } |
サーバ2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
using System; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.IO; using System.Text.RegularExpressions; namespace SimpSrv { public partial class Form1 : Form { bool chk; TcpListener listener = null; public Form1() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { if (listener != null) return; MessageBox.Show("起動しました。"); this.Text = "起動中"; IPAddress ip = IPAddress.Parse("192.168.102.9"); listener = new TcpListener(ip, 80); listener.Start(); TcpClient client = null; chk = true; while(true) { await Task.Run(() => { try { client = listener.AcceptTcpClient(); } catch (SocketException ex) { System.Diagnostics.Debug.Print(ex.Message.ToString()); } }); if (!chk) break; Encoding enc = Encoding.GetEncoding("shift_jis"); string resMsg = ""; string sendMsg = ""; using (NetworkStream ns = client.GetStream()) { ns.WriteTimeout = 10000; ns.ReadTimeout = 10000; using (MemoryStream ms = new MemoryStream()) { byte[] resByte = new byte[1024]; int resSize = 0; do { try { resSize = ns.Read(resByte, 0, resByte.Length); } catch (IOException ex) { System.Diagnostics.Debug.Print(ex.Message.ToString()); break; } if (resSize == 0) break; ms.Write(resByte, 0, resSize); } while (ns.DataAvailable); resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length); ms.Close(); } Regex reg = new Regex(@"\/\?name=([a-z]+)&id=([0-9]{6})&p=([0-9]{2})\s"); Match match = reg.Match(resMsg); if (match.Success) { sendMsg = "\n\n" + Html.MakeHtml(match.Groups[1].ToString(),match.Groups[2].ToString(),match.Groups[3].ToString()); } else { sendMsg = "\n\n" + "false"; } byte[] sendBytes = enc.GetBytes(sendMsg); try { ns.Write(sendBytes, 0, sendBytes.Length); } catch (IOException ex) { System.Diagnostics.Debug.Print(ex.Message.ToString()); } ns.Close(); } client.Close(); } } private void button2_Click(object sender, EventArgs e) { if (listener == null) return; MessageBox.Show("終了しました。"); this.Text = "停止中"; listener.Stop(); listener = null; chk = false; } } } |
C# 付箋紙プログラム
以下は未使用。
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
using System; using System.Windows.Forms; namespace sticker_notes { static class Program { /// <summary> /// アプリケーションのメイン エントリ ポイントです。 /// </summary> [STAThread] static void Main() { //Application.EnableVisualStyles(); //Application.SetCompatibleTextRenderingDefault(false); NotifyIcon ni = new System.Windows.Forms.NotifyIcon(); ni.Visible = true; ni.Icon = new System.Drawing.Icon(@"C:\Program Files\Windows Live\Writer\writer.ico");//適当なico ni.Click += new EventHandler((object sender, EventArgs e) => { Form1 f = new Form1(); f.Show(); }); ni.DoubleClick += new EventHandler((object sender, EventArgs e)=> { Application.Exit(); }); Application.Run(); } } } |
Form1.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
using System; using System.Drawing; using System.Windows.Forms; namespace sticker_notes { public partial class Form1 : Form { int mouseX; int mouseY; int mouseWith; int mouseHeight; Boolean FgWith = false; Boolean FgHeight = false; public Form1() { InitializeComponent(); this.FormBorderStyle = FormBorderStyle.None; //バーは消えるがサイズ変更できず。 //this.ControlBox = false; //this.Text = ""; //サイズ変更できるが境界線が消せない。 this.Opacity = 0.9; this.TopMost = true; TextBox tb = new System.Windows.Forms.TextBox(); tb.Dock = DockStyle.Fill; tb.Multiline = true; tb.Font = new Font("", 12); tb.BackColor = Color.Beige; this.Controls.Add(tb); tb.KeyDown += new KeyEventHandler(this.text_keydown); tb.MouseDown += new MouseEventHandler(this.mouse_down); tb.MouseMove += new MouseEventHandler(this.mouse_move); tb.MouseUp += new MouseEventHandler(this.mouse_up); } public void mouse_up(object sender, MouseEventArgs e) { FgWith = false; FgHeight = false; } public void mouse_down(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.mouseX = e.X; this.mouseY = e.Y; this.mouseWith = this.Width; this.mouseHeight = this.Height; } } public void mouse_move(object sender, MouseEventArgs e) { if (e.X > this.Width - 20 && e.X < this.Width && e.Y > this.Height - 20 && e.Y < this.Height && !FgWith && !FgHeight) { this.Cursor = Cursors.SizeNWSE; if (e.Button == MouseButtons.Left) { FgWith = true; FgHeight = true; } } else if (e.X > this.Width - 20 && e.X < this.Width && !FgHeight) { this.Cursor = Cursors.SizeWE; if (e.Button == MouseButtons.Left) FgWith = true; } else if (e.Y > this.Height - 20 && e.Y < this.Height && !FgWith) { this.Cursor = Cursors.SizeNS; if (e.Button == MouseButtons.Left) FgHeight = true; } if (FgWith && FgHeight && e.Button == MouseButtons.Left) { this.Width = mouseWith + e.X - this.mouseX; this.Height = mouseHeight + e.Y - this.mouseY; } else if (FgWith && e.Button == MouseButtons.Left) { this.Width = mouseWith + e.X - this.mouseX; } else if (FgHeight && e.Button == MouseButtons.Left) { this.Height = mouseHeight + e.Y - this.mouseY; } else if (!FgWith && !FgHeight && e.Button == MouseButtons.Left) { this.Left += e.X - this.mouseX; this.Top += e.Y - this.mouseY; } } public void text_keydown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) this.Close(); if (e.Control && e.KeyCode == Keys.A) (sender as TextBox).SelectAll(); } } } |
画像の場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System.Windows.Forms; namespace sticker_notes { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.FormBorderStyle = FormBorderStyle.None; PictureBox tb = new PictureBox(); tb.ImageLocation = Application.StartupPath + @"\1.jpg"; tb.Dock = DockStyle.Fill; tb.SizeMode = PictureBoxSizeMode.Zoom; this.Controls.Add(tb); } } } |
ここまで未使用。
サイズ変更の作りがおかしかったので、以下、修正版。画像を表示しておくため位置をxmlにシリアライズ。
Progam.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Windows.Forms; namespace sticker_notes { static class Program { /// <summary> /// アプリケーションのメイン エントリ ポイントです。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); NotifyIcon ni = new System.Windows.Forms.NotifyIcon(); ni.Visible = true; ni.Icon = new System.Drawing.Icon(Application.StartupPath + @"\i.ico"); ni.DoubleClick += new EventHandler((object sender, EventArgs e) => { Application.Exit(); }); Form1 f = new Form1(); f.Show(); Application.Run(); } } } |
Form1.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
using System; using System.Drawing; using System.Windows.Forms; namespace sticker_notes { public partial class Form1 : Form { int MouseX; int MouseY; int ThisW; int ThisH; Boolean FW = false; Boolean FH = false; public Form1() { InitializeComponent(); this.FormBorderStyle = FormBorderStyle.None; this.Opacity = 0.9; this.TopMost = false; this.ShowInTaskbar = false; PictureBox pb = new PictureBox(); pb.Dock = DockStyle.Fill; pb.ImageLocation = Application.StartupPath + @"\1.jpg"; pb.SizeMode = PictureBoxSizeMode.Zoom; this.Controls.Add(pb); pb.MouseUp += new MouseEventHandler(this.mouse_up); pb.MouseDown += new MouseEventHandler(this.mouse_down); pb.MouseMove += new MouseEventHandler(this.mouse_move); StartPosition = FormStartPosition.Manual; try { System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(int[])); using (System.IO.StreamReader sr = new System.IO.StreamReader(Application.StartupPath + @"\config", new System.Text.UTF8Encoding(false))) { int[] i = (int[])xs.Deserialize(sr); this.Width = i[0]; this.Height = i[1]; this.Top = i[2]; this.Left = i[3]; sr.Close(); } } catch (System.IO.FileNotFoundException e) { } } public void mouse_up(object sender, MouseEventArgs e) { FW = false; FH = false; System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(int[])); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(Application.StartupPath + @"\config",false,new System.Text.UTF8Encoding(false))) { xs.Serialize(sw, new int[] { this.Width, this.Height, this.Top, this.Left }); sw.Close(); } } public void mouse_down(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; this.MouseX = e.X; this.MouseY = e.Y; this.ThisW = this.Width; this.ThisH = this.Height; if (e.X > this.Width - 20 && e.X < this.Width && e.Y > this.Height - 20 && e.Y < this.Height) { FW = true; FH = true; } else if (e.X > this.Width - 20 && e.X < this.Width) { FW = true; } else if (e.Y > this.Height - 20 && e.Y < this.Height) { FH = true; } } public void mouse_move(object sender, MouseEventArgs e) { if (e.X > this.Width - 20 && e.X < this.Width && e.Y > this.Height - 20 && e.Y < this.Height) { this.Cursor = Cursors.SizeNWSE; } else if (e.X > this.Width - 20 && e.X < this.Width) { this.Cursor = Cursors.SizeWE; } else if (e.Y > this.Height - 20 && e.Y < this.Height) { this.Cursor = Cursors.SizeNS; } else { this.Cursor = Cursors.Default; } if (FW && FH) { this.Width = this.ThisW + e.X - this.MouseX; this.Height = this.ThisH + e.Y - this.MouseY; } else if (FW) { this.Width = ThisW + e.X - this.MouseX; } else if (FH) { this.Height = ThisH + e.Y - this.MouseY; } if (!FW && !FH && e.Button == MouseButtons.Left) { this.Left += e.X - this.MouseX; this.Top += e.Y - this.MouseY; } } } } |
これでデスクトップに画像を表示しておくことができる。
以下はテキスト用にForm1だけさらに修正。デスクトップに表示させておいてメモとして利用
Form1.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
using System; using System.Drawing; using System.Windows.Forms; namespace sticker_notes { public partial class Form1 : Form { int MouseX; int MouseY; int ThisW; int ThisH; Boolean FW = false; Boolean FH = false; Boolean Ctr = false; public Form1() { InitializeComponent(); this.FormBorderStyle = FormBorderStyle.None; this.Opacity = 0.9; this.TopMost = false; this.ShowInTaskbar = false; StartPosition = FormStartPosition.Manual; TextBox tb = new TextBox(); tb.Dock = DockStyle.Fill; tb.Multiline = true; tb.Font = new Font("メイリオ", 12); this.Controls.Add(tb); //tb.BackColor = Color.Transparent; //this.TransparencyKey = Color.White; try { System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(int[])); using (System.IO.StreamReader sr = new System.IO.StreamReader(Application.StartupPath + @"\config", new System.Text.UTF8Encoding(false))) { int[] i = (int[])xs.Deserialize(sr); this.Width = i[0]; this.Height = i[1]; this.Top = i[2]; this.Left = i[3]; sr.Close(); } System.Xml.XmlDocument xd = new System.Xml.XmlDocument(); xd.PreserveWhitespace = true; xd.Load(Application.StartupPath + @"\body"); xs = new System.Xml.Serialization.XmlSerializer(typeof(string)); using (System.Xml.XmlNodeReader xnr = new System.Xml.XmlNodeReader(xd.DocumentElement)) { tb.Text = (string)xs.Deserialize(xnr); xnr.Close(); } } catch (System.IO.FileNotFoundException e) { } tb.MouseUp += new MouseEventHandler(this.mouse_up); tb.MouseDown += new MouseEventHandler(this.mouse_down); tb.MouseMove += new MouseEventHandler(this.mouse_move); tb.TextChanged += new EventHandler(this.body_save); tb.KeyDown += new KeyEventHandler((object sender, KeyEventArgs e) => { if (e.Control && e.KeyCode == Keys.A) tb.SelectAll(); if (e.KeyCode == Keys.Escape) Application.Exit(); if (e.Control) Ctr = true; }); tb.KeyUp += new KeyEventHandler((object sender, KeyEventArgs e) => { Ctr = false; }); tb.GotFocus += new EventHandler((object sender, EventArgs e) => { this.Opacity = 0.9; }); tb.LostFocus += new EventHandler((object sender, EventArgs e) => { this.Opacity = 0.5; }); } public void body_save(object sender, EventArgs e) { System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(String)); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(Application.StartupPath + @"\body", false, new System.Text.UTF8Encoding(false))) { xs.Serialize(sw, ((TextBox)sender).Text); sw.Close(); } } public void mouse_up(object sender, MouseEventArgs e) { FW = false; FH = false; System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(int[])); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(Application.StartupPath + @"\config",false,new System.Text.UTF8Encoding(false))) { xs.Serialize(sw, new int[] { this.Width, this.Height, this.Top, this.Left }); sw.Close(); } } public void mouse_down(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; this.MouseX = e.X; this.MouseY = e.Y; this.ThisW = this.Width; this.ThisH = this.Height; if (e.X > this.Width - 20 && e.X < this.Width && e.Y > this.Height - 20 && e.Y < this.Height) { FW = true; FH = true; } else if (e.X > this.Width - 20 && e.X < this.Width) { FW = true; } else if (e.Y > this.Height - 20 && e.Y < this.Height) { FH = true; } } public void mouse_move(object sender, MouseEventArgs e) { if (e.X > this.Width - 20 && e.X < this.Width && e.Y > this.Height - 20 && e.Y < this.Height) { this.Cursor = Cursors.SizeNWSE; } else if (e.X > this.Width - 20 && e.X < this.Width) { this.Cursor = Cursors.SizeWE; } else if (e.Y > this.Height - 20 && e.Y < this.Height) { this.Cursor = Cursors.SizeNS; } if (FW && FH) { this.Width = this.ThisW + e.X - this.MouseX; this.Height = this.ThisH + e.Y - this.MouseY; } else if (FW) { this.Width = ThisW + e.X - this.MouseX; } else if (FH) { this.Height = ThisH + e.Y - this.MouseY; } if (!FW && !FH && e.Button == MouseButtons.Left && Ctr) { this.Left += e.X - this.MouseX; this.Top += e.Y - this.MouseY; } } } } |
Androidで取得した値をメールで確認
Androidで自動で値を収集して、それをレンサバにPOSTして、レンサバから自動でメール送信。
レンタルサーバーの設定
エックスサーバーのcronにスクリプトをフルパスで追加。
/home/xxx/xxx/script
のような感じにして、scriptのパーミッションは701に設定。
スクリプトの実体
tmp=`cat /xxx/xxx.txt`
echo “$tmp” | mail -s “title” mail@xxx.com
echo “” > /xxx/xxx.txt
これで、xxx.txtの値を定期送信する。
xxx.txtを作成するためのスクリプトは以下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php class App{ private function main(){ if(array_key_exists("key",$_POST) && array_key_exists("lux", $_POST) && $_POST["key"] == "xxx") { $tmp = file_get_contents("xxx.txt"); file_put_contents("xxx.txt",$_POST["lux"]."\n".$tmp); } } public function __construct(){ $this->main(); } } new App; |
ここでは単純POSTを受け取ったら作成する。
送信するのはAndroid
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
package com.example.sokamura.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.widget.TextView; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends AppCompatActivity implements SensorEventListener { SensorManager sm; TextView tv; MainActivity ma; String body = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView)findViewById(R.id.t); sm = (SensorManager)getSystemService(SENSOR_SERVICE); ma = this; Timer timer = new Timer(); timer.scheduleAtFixedRate( new TimerTask(){ @Override public void run(){ SubClass s = new SubClass(ma); s.execute(body); body = ""; } },0,1000*60*60*1);//1時間 } @Override protected void onStop() { super.onStop(); //sm.unregisterListener(this); } @Override protected void onResume() { super.onResume(); List<Sensor> sensors = sm.getSensorList(Sensor.TYPE_LIGHT); if(sensors.size() > 0) { Sensor s = sensors.get(0); sm.registerListener(this, s, SensorManager.SENSOR_DELAY_UI); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {} @Override public void onSensorChanged(SensorEvent event) { if(event.sensor.getType() == Sensor.TYPE_LIGHT) { String s = new SimpleDateFormat("MM/dd HH:mm:ss").format(new Date()) + " " + String.format("%.2f", event.values[0]); tv.setText(s); body = s + "\n" + body; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package com.example.sokamura.myapplication; import android.os.AsyncTask; import java.io.StringWriter; import java.io.PrintWriter; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; class SubClass extends AsyncTask<String,Integer,String> { //マニフェストにパーミッション追加 public SubClass(MainActivity param){} @Override protected void onPostExecute(String param){} @Override protected String doInBackground (String ... params) { HttpURLConnection con = null; try { URL url = new URL("http://xxx.com/xxx.php"); con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setDoOutput(true); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream()); out.write("key=xxx" + "&lux=" + URLEncoder.encode(params[0],"UTF-8")); out.close(); con.getInputStream(); return ""; } catch (Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); return ""; } finally { if (con != null) con.disconnect(); } } } |
WordPress カスタマイズ(更新含む)
記事一覧
・バージョンアップ時、再実行。
タイトル表示(投稿)を消す
・バージョンアップ時、再実行。
wp-content/themes/xxx/index.php
の中で以下のようにコメントアウトする。
1 2 3 4 5 6 7 8 9 10 11 |
<?php if ( is_home() && ! is_front_page() ) : ?> <header class="page-header"> <h1 class="page-title"><?php single_post_title(); ?></h1> </header> <?php else : ?> <!-- <header class="page-header"> <h2 class="page-title"><?php _e( 'Posts', 'twentyseventeen' ); ?></h2> </header> --> <?php endif; ?> |
テーマの幅変更
・バージョンアップ時、再実行。
wp-content/themes/xxx/style.css
の3408行(/* Layout */)以下、変更。
.wrap
max-width
を1000pxから1200px
.has-sidebar:not(.error404) #primary
width
を58%から62%
.has-sidebar #secondary
width
を36%から32%
(未使用)不要ファイル削除
・バージョンアップ時、再実行。
public_html
にて実行。
rm -i readme.html
rm -i license.txt
rm -i wp-config-sample.php
(未使用)Aタグアンダーバー非表示
・バージョンアップ時、再実行。
wp-content/themes/xxx/style.css
の中で
.entry-content a(1191行)
が含まれる
-webkit-box-shadow: inset 0 -1px 0 rgba(15, 15, 15, 1);
box-shadow: inset 0 -1px 0 rgba(15, 15, 15, 1);
をコメントアウト。
.entry-content a:focus(1237行)
.entry-content a:hover(1238行)
が含まれる
-webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0), 0 3px 0 rgba(0, 0, 0, 1);
box-shadow: inset 0 0 0 rgba(0, 0, 0, 0), 0 3px 0 rgba(0, 0, 0, 1);
をコメントアウト。
(未使用)Analytics/AdSense連携
・バージョンアップ時、再実行。
(未使用)タグ一覧で本文非表示
・バージョンアップ時、再実行。
wp-content/themes/xxx
の中に、
tag.php
を作成し以下のように記入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<?php get_header(); ?> <div class="wrap"> <div id="primary" class="content-area"> <main id="main" class="site-main" role="main"> <?php if (have_posts()){ while (have_posts()){ the_post(); echo '<header class="entry-header">'; if ('post' === get_post_type() ) { echo '<div class="entry-meta">'; echo twentyseventeen_time_link(); twentyseventeen_edit_link(); echo '</div><!-- .entry-meta -->'; }; the_title('<span class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></span>' ); echo "</header>"; } the_posts_pagination( array( 'prev_text' => twentyseventeen_get_svg( array( 'icon' => 'arrow-left' ) ) . '<span class="screen-reader-text">' . __( 'Previous page', 'twentyseventeen' ) . '</span>', 'next_text' => '<span class="screen-reader-text">' . __( 'Next page', 'twentyseventeen' ) . '</span>' . twentyseventeen_get_svg( array( 'icon' => 'arrow-right' ) ), 'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'twentyseventeen' ) . ' </span>', ) ); } ?> </main><!-- #main --> </div><!-- #primary --> <?php get_sidebar(); ?> </div><!-- .wrap --> <?php get_footer(); |
更新順ウィジェット
・プラグイン化済み
特定のページにJavaScriptを挿入
・プラグイン化済み
ここでは下記に挿入しているコード。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
add_action('wp_footer', 'get_time_range', 1); function get_time_range(){ if (!is_single('151')) return; echo <<<HTML <style> #sh,#sm,#ss,#eh,#em,#es { display: inline; } </style> <script> jQuery(window).on('load', function() { jQuery('#sh').on('change', ToSec); jQuery('#sm').on('change', ToSec); jQuery('#ss').on('change', ToSec); jQuery('#eh').on('change', ToSec); jQuery('#em').on('change', ToSec); jQuery('#es').on('change', ToSec); function ToSec(){ let startSec = (Number(jQuery('#sh').val()) * 60 * 60) + (Number(jQuery('#sm').val()) * 60) + Number(jQuery('#ss').val()); let endSec = (Number(jQuery('#eh').val()) * 60 * 60) + (Number(jQuery('#em').val()) * 60) + Number(jQuery('#es').val()); let rangeSec = endSec - startSec; jQuery('#cmd').text('ffmpeg -ss ' + startSec + ' -i i.mp4 -t ' + rangeSec + ' o.mp4'); } }); </script> HTML; } |
タグクラウドを投稿数順に変更
・プラグイン化済み
1 2 3 4 5 6 7 8 9 10 11 |
function args_customize($args) { $add_args = array( 'orderby' => 'count', 'order' => 'DESC', ); $args = wp_parse_args($args, $add_args); return $args; } add_action('widget_tag_cloud_args', 'args_customize'); |
タグクラウドにCSSを適用
・プラグイン化済み
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function tag_cloud_css(){ echo <<<HTML <style> .tagcloud li { font-size: 0.9em; } </style> HTML; } add_action('wp_footer', 'tag_cloud_css', 1); |
REST APIを無効化
・プラグイン化済み
パーマリンクが標準だと動かないが、塞がれているわけではないので注意。
http://okamurax.com/wp-json/wp/v2/posts
http://okamurax.com/?rest_route=/wp/v2/posts
1 2 3 4 |
function disable_rest() { return new WP_Error(); } add_action('rest_authentication_errors', 'disable_rest'); |
更新日を変更しない
更新日を更新しないチェックボックスを記事編集画面に追加。
・プラグイン化済み
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
add_action('admin_menu', function(){ add_meta_box('high_low', '更新日', function(){ echo '<div style="padding-top: 3px; overflow: hidden;">'; echo '<div style="width: 100px; float: left;"><input name="high_low" type="radio" value="high" checked="checked">更新する</div>'; echo '<div><input name="high_low" type="radio" value="low">更新しない</div>'; echo '</div>'; }, 'post', 'side', 'high'); }); add_action('save_post', function($post_id){ $high_low = isset($_POST['high_low']) ? $_POST['high_low'] : null; if("" == get_post_meta($post_id, 'high_low')) { add_post_meta($post_id, 'high_low', $high_low, true) ; } elseif($high_low != get_post_meta($post_id, 'high_low')) { update_post_meta($post_id, 'high_low', $high_low) ; } elseif("" == $high_low) { delete_post_meta($post_id, 'high_low') ; } }); add_filter('wp_insert_post_data', function($data, $postarr){ $high_low = isset($_POST['high_low']) ? $_POST['high_low'] : null; if($high_low == "low"){ unset($data["post_modified"]); unset($data["post_modified_gmt"]); } return $data; }, 10, 2); |
favicon設定
・初回のみ
header.phpとwp-login.php
のheadタグの中に以下を追加
1 |
<link rel="SHORTCUT ICON" href=<?php echo get_template_directory_uri(); ?>/favicon.ico /> |
ダッシュボード>外観>カスタマイズ>サイト基本情報>サイトアイコン
からも変更することができる。
パーミション変更
・初回のみ
find . -type d | xargs chmod 705
find . -type f | xargs chmod 604
find . -name “wp-config.php” | xargs chmod 600
IPアドレスでログインを弾く
・初回のみ+IPアドレス変更時
wp-login.phpのある階層の.htaccessに以下を追記
1 2 3 4 5 |
<files wp-login.php> order deny,allow deny from all allow from xxx.xxx.xxx.xxx </files> |
wp-adminの直下にある.htaccessにも以下を追記。
1 2 3 |
order deny,allow deny from all allow from xxx.xxx.xxx.xxx |
※orderにてallowとdeny各ディレクティブのどちらを先に評価するか順番を指定する。
order allow,deny:許可→拒否
order deny,allow:拒否→許可
・2.4以降
wp-login.phpの階層
1 2 3 4 5 6 7 8 |
<files wp-login.php> require all denied require ip xxx.xxx.xxx.xxx </files> <files xmlrpc.php> require all denied </files> |
wp-adminの直下
1 2 |
require all denied require ip xxx.xxx.xxx.xxx |
(未使用)ウィジットの最新の投稿を更新順に変更
wp-includes/widgets/class-wp-widget-recent-posts.php
の中にある
$r = new WP_Query()
の中に条件の連想配列があるので、以下を追加する。
‘orderby’=>’modified’
これで更新順になる。
Wordpressのバージョンアップ時に消えるときがある。
(未使用)更新日を表示
wp-includes/widgets/class-wp-widget-recent-posts.php
の中で以下のように変更
1 2 3 4 |
<span class="post-date"><br> 投稿:<?php echo get_the_date('Y-m-d',$recent_post->ID); ?> / 更新:<?php echo get_the_modified_date('Y-m-d',$recent_post->ID); ?> </span> |
(未使用)ナビメニュー非表示
wp-content/themes/xxx/header.php
の中にある
wp_nav_menu()
をコメントアウト
(未使用)トップページから特定カテゴリ非表示
functions.phpに以下を追加。
1 2 3 4 5 6 |
function ExcCat( $query ) { if ( $query->is_home()) { $query->set( 'cat', '-99' ); } } add_action( 'pre_get_posts', 'ExcCat' ); |
(未使用)Google検索ボックス追加
ウィジェットでテキストを追加する。
1 2 3 4 5 6 |
<form action="http://www.google.com/search"> <input type="hidden" name="hl" value="ja" /> <input type="hidden" value="http://okamurax.com/" name="as_sitesearch" /> <input type="text" name="q" size="25" /> <input type="submit" name="btnG" value="検索" /> </form> |
(未使用)ログイン状態でリダイレクト
1 2 3 4 5 6 7 |
<?php add_action('wp_head', 'login_state', 1); function login_state() { if (!is_user_logged_in()) wp_redirect('/wp-login.php'); } |
(未使用)自作タグクラウド
ウィジェットにショートコードを入れれば表示される。
1 2 3 4 5 6 7 8 9 10 11 12 |
function count_tag(){ echo '<ul>'; $tags = get_tags(); foreach($tags as $tag){ echo '<li>'; echo '<a href="' . get_tag_link($tag->term_id) . '">' . $tag->name . '[' . $tag->count . ']</a>'; echo '</li>'; } echo '</ul>'; } add_shortcode('count_tag', 'count_tag'); |
Apache+PassengerでRailsを動かす
passengerインストール(gem)
sudo gem install passenger
sudo /usr/local/bin/passenger-install-apache2-module
を実行する。(該当ファイルが見つからない場合。sudo find / -name “*passenger*” -type f)
最後に必要な追加が表示される。
sudo apt-get install libcurl4-openssl-dev
sudo apt-get install libcurl4-gnutls-dev
sudo apt-get install apache2-dev
sudo apt-get install libapr1-dev
sudo apt-get install libaprutil1-dev
表示されたとおり不足の機能をインストールして、もう一回以下を実行。
sudo /usr/local/bin/passenger-install-apache2-module
All goodと表示されるまで繰り返せばOKのハズだけど、今回は、
fatal error: openssl/pem.h: そのようなファイ ルやディレクトリはありません
と表示されてしまう。
必要な追加では表示されないが、opensshでエラーなので、
以下をインストールしてみる。
sudo apt-get install libssl-dev
インストールが無事終了すると、
LoadModule passenger_module /var/lib/gems/2.3.0/gems/passenger-5.1.2/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
PassengerRoot /var/lib/gems/2.3.0/gems/passenger-5.1.2
PassengerDefaultRuby /usr/bin/ruby2.3
</IfModule>
のように表示されるので、apacheの設定に追加する。
基本設定
もともとのDocumentRootは
/home/okamura/www
だったので、そこで
rails new test_app
を実行して新しいrailsのフォルダを作成してみた。
実体としては
/home/okamura/www/test_app
がrailsのプロジェクトフォルダとなる。
VirtualHostの項目で
DocumentRoot /home/okamura/www/test_app/public
として、開発なので以下を追加しておく。
RailsEnv development
これで問題なく動いた。
サブディレクトリで複数動かす場合
railsのpublicの実体が
/home/okamura/www/test_app/public
apacheのconfでのdocumentrootが
/home/okamura/www/test_app/public
とするのが基本。
サブディレクトリで複数のアプリを動かしたい場合。
apacheのconfでdocumentrootを
/home/okamura/www
にする。
RailsBaseURI /app1
RailsBaseURI /app2
を追加する。
railsのpublicの実体のシンボリックを作る。
sudo ln -s /home/okamura/ruby/asagao/public /home/okamura/www/app1
sudo ln -s /home/okamura/ruby/pico_planner/public /home/okamura/www/app2
apacheのconfはこんな感じ。
DocumentRoot /home/okamura/www
RailsBaseURI /app1
RailsBaseURI /app2
RailsEnv development
Ubuntu インストール用USBメモリ
USBメモリ接続後にdfコマンドを実行する。
表示の見方は
scsiデバイス、sda,sdb,sdc
ideデバイス、hda,hdb,hdc,hdd
のようになる。
今回は、dev/sdb1となった。しっかり覚えておく。
sudo dd if=/home/okamura/download/CentOS-7-x86_64-DVD-1611.iso of=/dev/sdb1 bs=32M
ifはフルパス。of=は出力先指定。間違えると大変。
watch -n 30 pkill -USR1 dd
USR1シグナルをddコマンドに送っている。
/media/okamura/の一覧にあるのでumountする。
sudo umount ESD-USB
MBRのコピーならこういう風に書く。
sudo dd if=/dev/sda1 of=/dev/sdb1 bs=446 count=1
USBブートしない場合、
BIOSの設定を変更する。
DELLの場合F2、ThinkPadはF1だった。
PCの電源関連
・ACアダプタ
規格が多いので基本的に純正を使うべき。
ACアダプタによくあるINPUTは消費量、OUTPUTはそこまで供給できる。ただし、INPUTに関してはほぼ家庭用電源に合わせてあるので、考える必要はない。
機器の電流はその電流以上で使ってくださいの意味で、機器とACアダプタの関係は以下の通り。(左が機器、右がACアダプタ)ACアダプタを純正品から汎用品などに変更する場合も同じ。(左が純正品、右が汎用品)
電圧 == 電圧 (V) ※アダプタが高いと機器が故障、低いと動作しない。
電流 < 電流 (A) ※アダプタが低いとアダプタが故障。
電力 <= 電力 (W)
極性 == 極性 (センタープラス / センターマイナス)
口経 == 口経
・その他の分類
AC-ACとAC-DCアダプター
PC(家電)はほぼAC-DCアダプターなので、心配する必要はない。
トランス式とスイッチング式。
トランス式は重く、スイッチング式は軽い。PC(家電)ではほぼスイッチング式なので、心配する必要はない。
安定化電源、非安定化電源。
スイッチング式は安定化電源となる。
***
ACアダプタがないデスクトップはPCの内部で直流に変換している。
・ケーブル
PCの電源ケーブルによくある
7A / 125Vは、そのケーブルで7A / 125Vまで流せるということ。
・実際の消費量
自宅にある機器の仕様を少し調べてみると、使い方などでかなり幅があるけど、概ね、デスクトップPCで50~150W、ノートPCで10~50W程度で、タブレットなどはさらに少ない感じ。
・USB PD(USB Power Delivery)
従来のUSBは5V*0.5A=2.5W
USB PDでは、
Aは3A/5A
Vは5V/9V/15V/20V/
の組み合わせで15W~100W
(EPR仕様では48Vもある)
60W以上は5A対応のケーブルが必要。
ノートPCの場合、アダプタの出力が小さいと充電されないことがあり、出力が大きくても機器を壊すことはない。
目安として45W以上であれば充電されないということはない。
・オームの法則
電圧 (V)=抵抗(R)*電流(A)
抵抗 (R)=電圧(V)/電流(A)
電流 (A)=電圧(V)/抵抗(R)
(電圧(V)は、電流(A)、抵抗(R)と比例。電流(A)と抵抗(R)は反比例)
V
A | R
W=V*A
A=W/V
Ubuntu ユーザー関連、パーミッション
ユーザ
ユーザ一覧
getent passwd
less /etc/passwd
区切られた内容は以下の通り。
・ユーザ名
・パスワード
・ユーザーID
・グループID
・コメント
・ホームディレクトリ
・利用シェル
ユーザ情報
id xxx
グループ
グループ一覧
getent group
less /etc/group
グループに所属ユーザの確認
getent group xxx
グループの作成
groupadd wp
グループにユーザを追加
usermod -aG wp www-data
ログインユーザの所属グループ
groups
groups ユーザ名
でもOK
***
実験として、/var/www/に直接ファイルをアップロードするための変更。
ちなみに、/var/www/はroot:rootだが、rootグループにはrootしか所属していないため、/var/wwwの所属グループを変更しても問題ない。
所属グループの書き込みを許可
sudo chmod g+w /var/www
所属グループの変更
sudo chown root:www-upload /var/www
グループの作成
sudo groupadd www-upload
グループにユーザを追加
sudo usermod -aG www-upload ubuntu
確認
groups ubuntu
WinSCPでアップロードするとubuntu:ubuntuの権限になる(デフォルトユーザーがubuntuなため)ので、/var/www/以下にフォルダ・ファイルをアップロードしてもサブフォルダも含めアクセスできるが、SSHでフォルダ・ファイルを作成すると権限がrootになるので、WinSCP経由では作業できないので注意。
***
sudoできるユーザ
/etc/sudoer
ubuntuの場合sudo、adminグループ
ubuntuではsudoグループがsudoできるグループ
adminというグループには誰も所属していない
ユーザ作成
sudo useradd xxx
mオプションを付けないと、ホームディレクトは作成されず、手動では/etc/skelの内容がコピーされない
useradd -D
デフォルトの確認
ユーザの削除
userdel -r xxx
mオプションでホームディレクトリの作成
(自動で、/etc/skelのコピーが入る)
sudo useradd -m inna
ログインできなユーザへ
sudo usermod -s /usr/sbin/nologin inna
ログインできるユーザへ
sudo usermod -s /bin/bash inna
参加するグループの変更
usermod -aG
chown
chown 所有者:所属グループ 対象
再帰の場合、
chown -R xxx/xxx
で再帰的にユーザ、グループを全て変えられる。
chmod
sudo chmod [ u / g / o / a ] [ + / – / = ] [ r / w / x ] 対象ファイル
u: ユーザー
g: グループ
o: その他
a: すべて
sudo chmod 764 hoge.txtのように指定することもできる
4: 読むことが可能(Read)
2: 書くことが可能(Write)
1: 実行が可能(eXecute)
0: なにもできない
権限の意味
ファイルの場合。
R
そのファイルを読み込む
W
そのファイルを書込める
X
バイナリなら実行できる。スクリプトなら、そのスクリプトを実行できる。
(スクリプトの実体はテキストファイルで先頭に#記号がある)
ディレクトリの場合。
R
そのディレクトリの中身をみる。
W
そのディレクトリにファイルを作成すること。
X
そのディレクトリをカレントディレクトリにすること。
(ディレクトリの実行権はサブディレクトリにも影響するが、RWは指定のフォルダだけ)
Ruby文法基礎
画面出力
puts 改行、print 改行なし
gets 入力
p はputs 変数.inspectと同じ
変数
ローカル変数
注意、変数のスコープは上位のスコープを探さない。
ブロック、メソッド、クラス/モジュール定義の終わりまで。
class Hoge
x = “bye”
def initialize
x = “hello”
puts x
end
end
h = Hoge.new #=> hello
インスタンス変数
class User
def say
puts @x
@x = “b”
puts @x
end
def self.say2
puts @x
@x = “a”
puts @x
end
end
User::say2
#=> 空白
#=> a
u = User.new
u.say
#=> 空白
#=> b
@を前置する
インスタンス生成時に作られない。値の代入時に実体が生成される。
クラス定義内で定義しない。
通常メソッド内で定義するがスコープはクラス内となる。
(ローカル変数の場合メソッド内だけになってしまう。)
使えるのはinitializeメソッドとインスタンスメソッドのみ
@前置きの変数をクラスメソッド内で操作してもインスタンス側に変更はない。
クラスメソッド内での@前置きの変数はクラスインスタンス変数として動作している模様。
クラス変数
class User
@@x = “hello”
def say
puts @@x
end
def self.say2
puts @@x
end
end
User::say2 #=> hello
u = User.new
u.say #=> hello
@@を前置して、クラス定義の中に書く。
クラスメソッド、インスタンスメソッド、クラス定義式内でアクセス可能
クラスインスタンス変数
class User
@x = “hello”
def say
puts @x
end
def self.say2
puts @x
end
end
User::say2 #=> hello
u = User.new
u.say #=> 空白
作り方は、@を前置きするのはインスタンス変数と一緒で、クラス定義内で定義するだけ。
機能はほぼクラス変数。違いはインスタンスメソッドからアクセスすることはできない
クラス・インスタンス変数のまとめ
@も@@もクラス内スコープ
ただ、@@はクラスで既に実体があるが、
@はインスタンス生成後、さらに代入などの処理があって実体ができる。
例えば、
class User
@x = “hello”
def say
puts @x
end
end
u = User.new
u.say
これでは空白が出力
@xを@@xにすればhelloが出力される。
class User
@@x = “hello”
def self.fst
@@x = “bye”
end
def say
puts @@x
end
end
User::fst
u = User.new
u.say #=> bye
クラス変数は実体がクラスにあるので、クラスメソッドでの変更後
インスタンスを生成すると変更の影響を受けている。
つまり、@も@@もスコープはクラスの変数。
@をクラスで定義したりクラスメソッドで定義すると、クラス変数と同様のクラスインスタンス変数になるが、
値を入れておいてもインスタンス生成時に値が破棄される。
(インスタンスでの@とクラスにある@が別のスコープの別変数として存在している)
継承についても注意が必要で、@@は継承後も値は破棄されないが、
@は継承時にインスタンス生成と同じように破棄される。
@も@@も共にスコープはクラスなので、@をクラス変数の様に使うことも可能だが、
そうすると、インスタンスや継承時の動作に注意が必要。
class User
@x = “hello”
def self.fst
puts @x
@x = “bye”
puts @x
end
def say
puts @x
end
end
User::fst
u = User.new
u.say
#=> hello
#=> bye
#=> 空白
@変数をクラス変数の代わりに利用。インスタンスで使わないなら問題ない。
グローバル変数
$を前置
スコープ無視
モジュール
module Hoge
x = “hello”
def self.say
x = “bye”
puts x
end
def sayHello
puts “Hello Hello”
end
end
Hoge::say #=> bye
ここのxはローカル変数であって、スコープ外なのでx=byeがないとエラー
class HogeHoge
include Hoge
end
HogeHoge::say
モジュールでのクラスメソッドはインクルードされない。
h = HogeHoge.new
h.say #=> NG
h.sayHello #=> Hello Hello
モジュールのクラスメソッドはインクルードされない。
インクルードされるのはインスタンスメソッドのみ
module Fuga
@x = “hey”
def self.say
puts @x
end
end
Fuga::say #=> hello
class FugaFuga
include Fuga
def say
puts @x
end
end
f = FugaFuga.new
f.say #=> 空白
Fugaでの変数が@@xならheyと表示される
ミックスインでも@@はインクルードされるけど、@は破棄されるということ。
演算子
=== は、ほとんど == と同じだけど、
正規表現 === 変数 だとマッチするかどうか、
クラス === 変数 だとそのクラスのオブジェクトかどうか判断する。
型
数値
Fixnum
Bignum
Float
型はないので自由な値が入る。入っている値によって
指し示すオブジェクトが変わる。
型の自動変換はないので、
to_s
to_f
to_i
文字列
連結は+
“”は式展開あり #{ xxx }
”は式展開なし
囲う
%q = ‘xxx’と同じ
%Q = “xxx”と同じ
% = “xxx”と同じ
%r{xxx} = /xxx/と同じ(正規表現)
%w(xxx,xxx,xxx) は配列(Wだと式展開あり)
配列
[“dog”,”cat”]
include?
length
empty?
などのメソッドがある。
追加は <<
要素を超えて、取り出すとnil、加えると自動で大きくなる。
オブジェクトなら何でもはいる。
条件分岐
0,や空文字もtrueになる。falseはnilとfalseだけ。
比較演算子はtrue/falseを返す b = (a == c)等
条件分岐に入ると、真偽問わず、スコープの中にある変数は初期化される。
スコープ
if,for,while,case
などの条件式で、スコープを作らない。
メソッド、ブロックではスコープができる。
x = “hello”
def fnc
x = “bye”
puts x
end
puts x
fnc
#=> hello
#=> bye
面白いのは、インスタンス変数でも同じということ
これは既にmainというクラスの中にいるから。
@x = “hello”
def fnc
@x = “bye”
puts @x
end
puts @x
fnc
#=> hello
#=> bye
クラスで囲うとどうなるか。
class User
@x = “hello” #<1>
def fnc
@x = “bye”
puts @x
end
puts @x #<2>
end
u = User.new
u.fnc
#=> hello
#=> bye
この結果も同じだけど、これはインスタンス生成時に、classが評価されて、
最初のhelloが出力されている。実際、u.fncを呼ばなくてもhelloは出力されるし、
<1><2>のどちらかを消すとhelloを出力されない。
そのあとのbyeは普通どおりインスタンスからfncを呼んでいるから出力される。
インスタンス生成後も@x = “hello”は生きているけど、それはクラスのスコープであって
インスタンスには存在しない。
class User
def fnc
@x = “b”
puts @x
end
def fnc2
puts @x
end
end
u = User.new
u.fnc
u.fnc2
#=> b
#=> b
インスタンス変数はクラススコープなので、最初fncでbが入り、次のfnc2でもその値が生きている。
fncをせずにfnc2を呼ぶと空白が出力される。
メソッド
途中で抜ける場合 returnも使える。
初期値を指定できる
def xx(var = “hello”)
end
引数の数量不定にすると配列になる
def fuc(*var)
end
第1引数はfstに入り、それ以降がvarの配列へ
def fuc(fst, *var)
end
名称について
? = true/falseを返す
! = 破壊的メソッド
ブロック
メソッド呼び出し時に定義する。メソッドに渡す処理の塊。
渡したメソッド内ではなく、ブロックを定義したスコープにいる。
yieldでメソッド側からブロックに引数を渡せる。
例外処理
begin
rescue
例外時
else
例外がない場合
end
メソッドなら
def
rescue
例外時
else
例外がない場合
end
とも書ける。
rescue => 変数で取り出す。
ハッシュ
population = {“France”=>100}
puts population [“France”]
キーがシンボルなら、以下の書き方ができる。
pop = {:fr => 100 }
なら、
pop = { fr:100 }
とできる。(スペースはいれない)
取り出すときは
pop [:fr]
となる。
範囲
1..10 # 1から10まで
1…10 # 1から9まで
正規表現
=~ で比較できる。
!~ は逆
string.gsubで置き換え。
日付
日時はTimeクラス
Dateオブジェクトは日付だけを扱う
日時の取り出し
t = Time.now
t.year
t.month
t.day
t.hour
t.min
t.sec
作る時
Time.local(2015,12,31,23,59,59)
整形はstrftime
t = Time.now
t.strftime(“%Y/%m/%d %H:%M”)
参照渡し
参照の値渡しになっている。
str1 = “hello”
str2 = “goodbye”
print “str1=”, str1.object_id, “\n”
print “str2=”, str2.object_id, “\n”
str1 = str2 #ここでstr1もstr2も”goodbye”を指している
str1.upcase!
print “str1=”, str1.object_id, “\n”
print “str2=”, str2.object_id, “\n”
puts str1,str2
str1=71129430
str2=71129420
str1=71129420
str2=71129420
GOODBYE
GOODBYE
クラスとメソッドについて
ドット記法はメソッド呼び出し
レシーバ.メソッド
二重コロンは
定数呼び出し、メソッドも呼べる。
rubyのインスタンスの内部的にはインスタンス変数とメソッドへのリンクだけ。
メソッドの定義はクラスに持っている。
ただ、通常のメソッド定義だとインスタンスに紐付いてクラスから直接呼べない
インスタンスメソッドをクラスから呼ぶNG
class Hoge
def piyo
”hoge”
end
end
p Hoge.piyo #=> undefined method
インスタンスメソッドをインスタンスから呼ぶOK
class Hoge
def piyo
”hoge”
end
end
h = Hoge.new
p h.piyo #=> hoge
クラスメソッドをクラスから呼ぶOK
class Hoge
def self.piyo
”hoge”
end
end
p Hoge.piyo #=> hoge
クラスメソッドをインスタンスから呼ぶNG
class Hoge
def self.piyo
”hoge”
end
end
h = Hoge.new
p h.piyo
と分けられる。
アクセサメソッド
自動で生成したい場合、インスタンス変数の名前をシンボルで渡す。
attr_accessor :name
そうすると、以下の2つのメソッドを自動で作る。
name=(value) # setter
name # getter
実体は以下のような感じ
class User
def name
@name
end
def name=(name)
@name = name
end
end
それぞれ1つだけでいい場合。
attr_reader :name
attr_writer :name
クラス内でアクセッサメソッドを呼ぶ時、
レシーバを省略して呼ぶと、ローカル変数とみなされてしまうので注意
メソッドのアクセス範囲
public
どこからでも
private
同クラス、サブクラスから読める。
レシーバ付けられない。関数形式でしか呼び出せない。
protected
同クラス、サブクラスから読める
レシーバ付けられる。
そのメソッドを持つオブジェクトがselfの場所でのみ呼び出せる